How to Use Projection in MongoDB?
In mongodb, projection means selecting only necessary data rather than selecting the whole data of a document. If a document has 5 fields and you need to show only 3, then select only 3 fields from it. There are a few projection operators that mongodb provides and helps us reach that goal.
Let us discuss about those operators in detail below.
$:
At first we are going to talk about $ operator. This operator limits the contents of the field that is included in the query results to contain the first matching element.
- It must required to appear the field in the query document.
- One positional $ operator can only be appear in the projection document.
- At a time only one array field can be appear in the query document.
Now let us see a basic example of this operator.
db.collection.find( { : ... },{ ".$": 1 } )
In the above example as you can see we have used find() on a collection. The method holds only 1 value for the array. It specifies that in a single query only one value can be retrieved from the array depending on the position.
Array Field Limitation:
Since only one array field can appear in the query document, if the array contains documents, to specify criteria on multiple fields of these documents, what can we use?
$elematch:
In MongoDB the $elemMatch projection operator is used to limits the contents of an array field which is included in the query results to contain only the first matching element in the array, according to the specified condition.
- The elements of the array are documents.
- If multiple elements match the $elemMatch condition, the operator returns the first matching element in the array.
- The $elemMatch projection operator is similar to the positional $ projection operator.
To describe an example about this operator we have to have a database where the db consists a lot of document type data. In my opinion a student mark-sheet is appropriate for this. Let us see the query.
db.grades.find( { records: { $elemMatch: { student: "stud1", grade: { $gt: 85 } } } } );
This example returns all documents in the grades collection where any element in the records array satisfies all of the conditions in the $elemMatch expression. This example returns all documents in the grades collection where the records array contains at least one element with both student equal to stud1 and grade greater than 85.
But what happens if there are two parameter stating 2 different grades of the same student. Like this:
db.grades.find( { records: { $elemMatch: { student: "stud1", grade: { $gt: 85 } } , : { student: "stud1", grade: { $gt: 90 } } } } );
because only 1 parameter is matched in the above query the output will show perfectly. In $elematch any 1 parameter has to match. However in the next case:
db.grades.find( { records: { $elemMatch: { student: "stud1", grade: { $gt: 85 } } , : { student: "stud2", grade: { $gt: 90 } } } } );
It would not match the query because no embedded document meets the specified criteria.
The differences in the projection operators:
The positional ($) projection operator:
- limits the contents of an array field that is included in the query results to contain the first element that matches the query document.
- requires that the matching array field is included in the query criteria
- can only be used if a single array field appears in the query criteria
- can only be used once in a projection
The $elemMatch projection operator
- limits the contents of an array field that is included in the query results to contain only the first array element that matches the $elemMatch condition.
- does not require the matching array to be in the query criteria
- can be used to match multiple conditions for array elements that are embedded documents
$slice
The $slice operator controls the number of items of an array that a query returns. For information on limiting the size of an array during an update with $push, see the $slice modifier instead.
Let us see a basic query:
db.collection.find( { field: value }, { array: {$slice: count } } );
This operation selects the document collection identified by a field named field that holds value and returns the number of elements specified by the value of count from the array stored in the array field. If count has a value greater than the number of elements in array the query returns all elements of the array.
$slice accepts arguments in a number of formats, including negative values and arrays.
As you saw the basic code, let us see how we can retrieve a set of comments from an array. Let us look below:
db.posts.find( {}, { comments: { $slice: 5 } } )
Here, $slice selects the first five items in an array in the comments field.
db.posts.find( {}, { comments: { $slice: -5 } } )
This operation returns the last five items in array.
So, we have first and last five comments. But what happens if we need a certain amount of comments from between the array? You have to modify the above code a little bit. As follows:
db.collection.find( { field: value }, { array: {$slice: [skip,limit] } } );
so, in the above code we can see a pair of parameters. Which tells us how to select data from between the array. How you ask?
As the first parameter you can see that we have used skip. Which tells us how many positions in the array we have to skip to start the count. And in the second we have limit, which tells us where the count will stop? Let us modify the above example for better understanding:
db.posts.find( {}, { comments: { $slice: [5,10] } } )
in the above example instead showing the first 5 comments, w have skipped them. After skipping, from the fifth position (because array positioning starts from 0) the limit count will start.
$meta
The $meta projection operator returns for each matching document the metadata (e.g. “textScore”) associated with the query. The $meta expression can be a part of the projection document as well as a sort() expression.
A $meta expression has the following syntax:
{ <projectedFieldName>: { $meta: <metaDataKeyword> } }
A textscore returns the score associated with the corresponding query:$text query for each matching document. The text score signifies how well the document matched the stemmed term or terms. If not used in conjunction with a query. Default order is descending.
As a basic example we can see the following set of codes:
db.collection.find( , { score: { $meta: "textScore" } } )
The $meta expression can be part of a sort() expression. We will get into detail later.
db.collection.find( , { score: { $meta: "textScore" } } ).sort( { score: { $meta: "textScore" } } )
Summary:
As in databases finding information is a very important aspect, same we can call about projection in mongodb. Although in this article we have scratched the surface of the projection. Saying that you can understand that there are many other ways we can use the find() for projecting a certain result in mongodb.
Reference: | How to Use Projection in MongoDB? from our JCG partner Piyas De at the Phlox Blog blog. |