What is MongoDB Projection?

Read it in 5 Mins

Last updated on
04th May, 2021
Published
29th Apr, 2021
Views
4,484
What is MongoDB Projection?

We can use MongoDB projection to pick specific data (which is considered necessary) instead of selecting all the data from the document. For example, consider that you have 10 fields in your document of which you need only 5, then you will use MongoDB projection operators for picking these required 5 fields.

Projection is most useful when choosing the required data from entire documents, especially for operators such as MongoDB $, $elemMatch, $slice, and $Meta. Through projection, we can improve database performance.

The MongoDB projection is a query where the fields we want to return can be specified. In MongoDB, we can do projection by adding a 0 or 1, following the name of the fields, including a query. If you specify parameter 1, it will be displayed and 0 will be hidden.

Example of MongoDB Projection:

Let’s understand MongoDB projection with an example. The following documents are provided in a collection called studentdata. 

> db.studentdata.find().pretty() 
{ 
        "_id" : ObjectId("59bf61230be1d6660c3982af"), 
        "student_name" : "Carlos", 
        "student_id" : 2000, 
        "student_age" : 20 
} 
{ 
        "_id" : ObjectId("59bf61500be1d6660c3982b0"), 
        "student_name" : "Ben", 
        "student_id" : 2001, 
        "student_age" : 21 
} 
{ 
        "_id" : ObjectId("59bf61650be1d6660c3982b1"), 
        "student_name" : "Jimmy", 
        "student_id" : 2002, 
        "student_age" : 20 
}

We’ll use the projection like this to obtain only the student_id for all documents:

> db.studentdata.find({}, {"_id": 0, "student_id": 1})
{ "student_id" : 2000}
{ "student_id" : 2001}
{ "student_id" : 2002}

Value 1 means the field is shown and Value 0 means the field is not shown. In Projection, when we set a field to 1, other fields are automatically set to 0, except _id, so we must set 0 in the projection to avoid _id.

Sometimes you may get errors while using projection in the query. This is done if some of the fields are set to 0 and some are set to 1, i.e. mix inclusion and exclusion, the only exception is the _id field.

Query that would produce error:

db.studentdata.find({}, {"_id": 0, "student_name": 0, "student_age": 1})

We have set student_name to 0 and other field student_age to 1. This is because we cannot mix them. You can set the fields you don’t want to display to 0 and set the fields you do want to display to 1.

Syntax:

With the db.collection.find() method, you can use projection. The second parameter in this approach is to show which fields are returned in the corresponding documents by means of the projection parameter. 

db.collection.find({}, {field1: value1, field2: value2, ..})

  • If the field value is set to 1 or true, the field will be included in the return document.
  • If the field value is set to 0 or false, it means that the field does not appear in the return document.
  • The use of projection operators is permitted, but the find() method cannot support $, $elemMatch, $slice, and $meta projection operators.
  • The method find() always returns _id unless you set _id field to 0. There is no need to set _id to 1 for returning _id.

Usage Considerations:

The $ operator projects in a set the first matching array element of any document based on certain requirements of the query statement.

An explicit condition argument is used for the $elemMatch projection operator. This allows you to project on the basis of a condition not in the query or to project in embedded documents on the basis of multiple fields.

$ Operator:

The $ operator is used to restrict an array’s contents to project the first element to fit the query condition on the array field. The first element will be returned in the specified array when no query condition is present.

Syntax:

db.collection.find( { <array>: <condition> ... }, { "<array>.$": 1 } )

Limitations:

  • In a single query, only one $ operator can be used.
  • The question must consist of only one condition in the array field in which it is applied.
  • Before the $-operator, the sort() function is used for the find() method. The order of the sort may not be correctly expressed by this function.
  • Only at the end of a field path can the $ operator be implemented.
  • The expression $slice can’t be used as a part of the same expression with $ Operator.
  • For example, the following projection may lead to undefined behaviour:
db.collection.find( { <array>: <value1>, <someOtherArray>: <value2> },
                    { "<array>.$": 1 } )

The query document should contain only one condition in the array field to which it is applied. Multiple conditions can intersect and lead to undefined behaviour.

Use the $elemMatch query operator to define criteria for multiple fields of documents in the array.

$elemMatch Operator:

The $elemMatch operator will restrict the array content to the first element matching a particular condition. This requirement is different from the $ operator since an explicit condition argument is needed for the $elemMatch projection operator.

An explicit condition argument is used for the $elemMatch projection operator. This allows you to project on the basis of a condition not in your query or to project in embedded documents on the basis of multiple fields.

Syntax:

db.collection.find( { <array>: <condition> ... }, { "<array>.$elemMatch": ($elemMatch operator) } )

Example:

db.players.insert( {
   name: "ben",
   games: [ { game: "cricket", score: 8 }, { game: "xyz", score: 5 } ],
   joined: new Date("2021-02-01"),
   lastLogin: new Date("2021-05-01")
} )
The projection returns the field of games though the field before joined and lastLogin fields are listed in the document:

db.players.find( {}, { games: { $elemMatch: { score: { $gt: 5 } } }, joined: 1, lastLogin: 1 } )

The operation returns the following document:
{
   "_id" : ObjectId("5edef64a1c099fff6b033977"),
   "joined" : ISODate("2020-01-01T00:00:00Z"),
   "lastLogin" : ISODate("2020-05-01T00:00:00Z"),
   "games" : [ { "game" : "cricket", "score" : 8 } ]
}

Limitations:

  • Regardless of how fields are placed in the document, the last field in the document would be the field on which $elemMatch is applied.
  • Find() on MongoDB views does not support the operator for $elemMatch projection.
  • The $elemMatch operator does not accept $text query expressions.

$slice Projection Operator:

The $slice operator determines how many elements the query output should return.

When the $slice projection is in the exclusion projection, other fields of the nested document are returned in the operation.

Syntax:

db.collection.find( <query>,  { <array Field>: { $slice: <number> } })

Limitations:

  • The $slice operator can only return the sliced element. No other object in an array will be returned.
  • Since the MongoDB constraint is used, the $slice operator should not be used along with the $ projection operator, while top-level fields have $ (dollar sign) as a part of the name of a field.
  • The $slice of the array and a field embedded in the array cannot be contained in queries for the same statement to prevent MongoDB path collisions.
    For example, the following operation is invalid:

db.inventory.find( { "instock.qty": { $gt: 25 } }, { "instock.$": { $slice: 1 } } )

In earlier versions, MongoDB has a limitation that high-ranking field names cannot begin with the dollar ($) symbol.

$meta Operator:

The $meta operator is used to obtain a document’s metadata. For both MongoDB aggregation and MongoDB projection, the $meta operator can be used.

Syntax:

{ $meta: <metaDataKeyword> }

Usage in Projection:

  • The expression { $meta: “textScore” } can be used as part of the text score metadata of a projection document.
  • Inclusion or exclusion projection may include the $meta expression.
  • The metadata “textScore” sorts in descending order.
  • To use the { $meta: “textScore” } expression in a sorting procedure, set the name of the field to an arbitrary one. The query system does not take account of the field name.
  • For debugging purposes only, and not for application logic, the { $meta: “indexKey”} expression is used
  • The {$meta:”indexKey”} expression is preferable over the cursor.returnKey expression ().

Project Fields to Return from Query:

All fields in matching documents return queries at MongoDB. You may provide a projection document to define or restrict fields to return or restrict the amount of data which MongoDB sends to applications.

Example:

db.inventory.insertMany( [
{ item: “journal”, status: “A”, size: { h: 14, w: 21}, instock: [ { store: “A”, qty: 5 } ] },
{ item: “notebook”, status: “A”, size: { h: 8.5, w: 11}, instock: [ { store: “C”, qty: 5 } ] },
{ item: “paper”, status: “D”, size: { h: 8.5, w: 11}, instock: [ { store: “A”, qty: 60 } ] },
{ item: “planner”, status: “D”, size: { h: 22.85, w: 30}, instock: [ { store: “A”, qty: 40 } ] },
{ item: “postcard”, status: “A”, size: { h: 10, w: 15.25}, instock: [ { store: “B”, qty: 15 }] }
]);

Return All Fields in Matching Documents:

If a projection document is not specified, all fields in the matched documents are returned by the db.collection.find() method.

This example shows all the fields in the inventory list of all documents in which the status is “D”:

db.inventory.find( { status: “D” } )

Conclusion:

By using MongoDB projection, we can control the display of data at the front end, thus enhancing its actual use in real world scenarios. In recent years, MongoDB has reached several milestones. This has enhanced the adoption of MongoDB and several companies are in search of full-stack developers with MongoDB expertise.

We can use the MongoDB projection to select specific data (which was needed) instead of selecting all data from the document. We can use MongoDB projection operators if we have a large number of fields in our document and only some fields are required.

Profile

Abhresh Sugandhi

Author

Abhresh is specialized as a corporate trainer, He has a decade of experience in technical training blended with virtual webinars and instructor-led session created courses, tutorials, and articles for organizations. He is also the founder of Nikasio.com, which offers multiple services in technical training, project consulting, content development, etc.