$ (projection)
Definition
$
The positional
$
operator limits the contents of an<array>
to return the first element that matches the query condition on the array.Use
$
in the projection document of thefind()
method or thefindOne()
method when you only need one particular array element in selected documents.See the aggregation operator
$filter
to return an array with only those elements that match the specified condition.
Usage Considerations
Both the $
operator and the $elemMatch
operator project
the first matching element from an array based on a condition.
The $
operator projects the first matching array element from each
document in a collection based on some condition from the query statement.
The $elemMatch
projection operator takes an explicit condition
argument. This allows you to project based on a condition not in the query, or
if you need to project based on multiple fields in the array's embedded documents.
See Array Field Limitations for an example.
db.collection.find()
operations on views do not support $
projection operator.
Behavior
Syntax
To return the first array element that matches the specified query condition on the array:
db.collection.find( { <array>: <condition> ... }, { "<array>.$": 1 } ) db.collection.find( { <array.field>: <condition> ...}, { "<array>.$": 1 } )
Changed in version 4.4: You can use the $
operator to limit an <array>
field which does not appear in the
query document. In previous
versions of MongoDB, the <array>
field being limited
must appear in the query document.
db.collection.find( { <someOtherArray>: <condition> ... }, { "<array>.$" : 1 } )
Important
To ensure expected behavior, the arrays used in the query document and the projection document must be the same length. If the arrays are different lenghts, the operation may error in certain scenarios.
Array Field Limitations
MongoDB requires the following when dealing with projection over arrays:
Only one positional
$
operator may appear in the projection document.Only one array field should appear in the query document. Additional array fields in the query document may lead to undefined behavior.
For example, the following projection may lead to undefined behavior:
db.collection.find( { <array>: <value>, <someOtherArray>: <value2> }, { "<array>.$": 1 } ) The query document should only contain a single condition on the array field to which it is applied. Multiple conditions may override each other internally and lead to undefined behavior.
To specify criteria on multiple fields of documents inside that array, use the
$elemMatch
query operator. The following query returns the first document inside agrades
array that has amean
of greater than 70 and agrade
of greater than 90.db.students.find( { grades: { $elemMatch: { mean: { $gt: 70 }, grade: { $gt:90 } } } }, { "grades.$": 1 } ) You must use the
$elemMatch
operator if you need separate conditions for selecting documents and for choosing fields within those documents.
Sorts and the Positional Operator
When the find()
method includes a
sort()
, the find()
method applies the sort()
to order the matching
documents before it applies the positional $
projection operator.
If an array field contains multiple documents with the same field
name and the find()
method includes a
sort()
on that repeating field, the returned
documents may not reflect the sort order because the sort was
applied to the elements of the array before the $
projection operator.
Positional Operator Placement Restriction
Starting in MongoDB 4.4, the $
projection operator can
only appear at the end of the field path; e.g. "field.$"
or "fieldA.fieldB.$"
.
For example, starting in MongoDB 4.4, the following operation is invalid:
db.inventory.find( { }, { "instock.$.qty": 1 } ) // Invalid starting in 4.4
To resolve, remove the component of the field path that follows the
$
projection operator.
In previous versions, MongoDB ignores the part of the path that follows
the $
; i.e. the projection is treated as "instock.$"
.
Positional Operator and $slice
Restriction
Starting in MongoDB 4.4, find
and findAndModify
projection
cannot include $slice
projection expression as part of a
$
projection expression.
For example, starting in MongoDB 4.4, the following operation is invalid:
db.inventory.find( { "instock.qty": { $gt: 25 } }, { "instock.$": { $slice: 1 } } ) // Invalid starting in 4.4
In previous versions, MongoDB returns the first element
(instock.$
) in the instock
array that matches the query
condition; i.e. the positional projection "instock.$"
takes
precedence and the $slice:1
is a no-op. The "instock.$": {
$slice: 1 }
does not exclude any other document field.
Examples
Project Array Values
A collection students
contains the following documents:
{ "_id" : 1, "semester" : 1, "grades" : [ 70, 87, 90 ] } { "_id" : 2, "semester" : 1, "grades" : [ 90, 88, 92 ] } { "_id" : 3, "semester" : 1, "grades" : [ 85, 100, 90 ] } { "_id" : 4, "semester" : 2, "grades" : [ 79, 85, 80 ] } { "_id" : 5, "semester" : 2, "grades" : [ 88, 88, 92 ] } { "_id" : 6, "semester" : 2, "grades" : [ 95, 90, 96 ] }
In the following query, the projection { "grades.$": 1 }
returns only the first element greater than or equal to 85
for the grades
field.
db.students.find( { semester: 1, grades: { $gte: 85 } }, { "grades.$": 1 } )
The operation returns the following documents:
{ "_id" : 1, "grades" : [ 87 ] } { "_id" : 2, "grades" : [ 90 ] } { "_id" : 3, "grades" : [ 85 ] }
Although the array field grades
may contain multiple elements
that are greater than or equal to 85
, the $
projection operator returns only the first matching element from the
array.
Project Array Documents
A students
collection contains the following documents
where the grades
field is an array of documents; each document
contain the three field names grade
, mean
, and std
:
{ "_id" : 7, semester: 3, "grades" : [ { grade: 80, mean: 75, std: 8 }, { grade: 85, mean: 90, std: 5 }, { grade: 90, mean: 85, std: 3 } ] } { "_id" : 8, semester: 3, "grades" : [ { grade: 92, mean: 88, std: 8 }, { grade: 78, mean: 90, std: 5 }, { grade: 88, mean: 85, std: 3 } ] }
In the following query, the projection { "grades.$": 1 }
returns only the first element with the mean
greater
than 70
for the grades
field:
db.students.find( { "grades.mean": { $gt: 70 } }, { "grades.$": 1 } )
The operation returns the following documents:
{ "_id" : 7, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 8 } ] } { "_id" : 8, "grades" : [ { "grade" : 92, "mean" : 88, "std" : 8 } ] }