Definition
$[<identifier>]New in version 3.6.
The filtered positional operator
$[<identifier>]identifies the array elements that match thearrayFiltersconditions for an update operation, e.g.db.collection.update()anddb.collection.findAndModify().Used in conjunction with the
arrayFiltersoption, the$[<identifier>]operator has the following form:{ <update operator>: { "<array>.$[<identifier>]" : value } }, { arrayFilters: [ { <identifier>: <condition> } ] } Use in conjunction with the
arrayFiltersoption to update all elements that match thearrayFiltersconditions in the document or documents that match the query conditions. For example:db.collection.updateMany( { <query conditions> }, { <update operator>: { "<array>.$[<identifier>]" : value } }, { arrayFilters: [ { <identifier>: <condition> } ] } ) Note
The
<identifier>must begin with a lowercase letter and contain only alphanumeric characters.For an example, see Update All Array Elements That Match
arrayFilters.
Behavior
In MongoDB 4.4 and earlier, update operators process document fields in lexicographic order. See Update Operators Behavior for details.
Restrictions
The arrayFilters option cannot include the following query
operators:
upsert
If an upsert operation results in an insert, the query must
include an exact equality match on the array
field in order to use $[<identifier>] in the update statement.
For example, the following upsert operation, which uses $[<identifier>]
in the update document, specifies an exact equality match condition
on the array field:
db.collection.update( { myArray: [ 0, 1 ] }, { $set: { "myArray.$[element]": 2 } }, { arrayFilters: [ { element: 0 } ], upsert: true } )
If no such document exists, the operation would result in an insert of a document that resembles the following:
{ "_id" : ObjectId(...), "myArray" : [ 2, 1 ] }
If the upsert operation did not include an exact equality match and no matching documents were found to update, the upsert operation would error. For example, the following operations would error if no matching documents were found to update:
db.array.update( { }, { $set: { "myArray.$[element]": 10 } }, { arrayFilters: [ { element: 9 } ], upsert: true } )
The operation would return an error that resembles the following:
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 2, "errmsg" : "The path 'myArray' must exist in the document in order to apply array updates." } })
Nested Arrays
The filtered positional operator $[<identifier>] can
be used for queries which traverse more than one array and nested arrays.
For an example, see Update Nested Arrays in Conjunction with $[].
Examples
Update All Array Elements That Match arrayFilters
Consider a collection students with the following documents:
{ "_id" : 1, "grades" : [ 95, 92, 90 ] } { "_id" : 2, "grades" : [ 98, 100, 102 ] } { "_id" : 3, "grades" : [ 95, 110, 100 ] }
To update all elements that are greater than or equal to 100 in the
grades array, use the filtered positional operator
$[<identifier>] with the arrayFilters:
db.students.update( { }, { $set: { "grades.$[element]" : 100 } }, { multi: true, arrayFilters: [ { "element": { $gte: 100 } } ] } )
The positional $[<identifier>] operator acts as a
placeholder for all elements in the array field that match the
conditions specified in arrayFilters.
After the operation, the students collection contains the following
documents:
{ "_id" : 1, "grades" : [ 95, 92, 90 ] } { "_id" : 2, "grades" : [ 98, 100, 100 ] } { "_id" : 3, "grades" : [ 95, 100, 100 ] }
Update All Documents That Match arrayFilters in an Array
The $[<identifier>] operator facilitates updates to arrays
that contain embedded documents. To access the fields
in the embedded documents, use the dot notation on the $[<identifier>].
db.collection.update( { <query selector> }, { <update operator>: { "array.$[<identifier>].field" : value } }, { arrayFilters: [ { <identifier>: <condition> } } ] } )
Consider a collection students2 with the following documents:
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" : 85, "std" : 6 } ] } { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 75, "std" : 6 }, { "grade" : 87, "mean" : 90, "std" : 3 }, { "grade" : 85, "mean" : 85, "std" : 4 } ] }
To modify the value of the mean field for all elements in the
grades array where the grade is greater than or equal to 85,
use the positional $[<identifier>] operator and
arrayFilters:
db.students2.update( { }, { $set: { "grades.$[elem].mean" : 100 } }, { multi: true, arrayFilters: [ { "elem.grade": { $gte: 85 } } ] } )
After the operation, the collection has the following documents:
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 100, "std" : 4 }, { "grade" : 85, "mean" : 100, "std" : 6 } ] } { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 100, "std" : 6 }, { "grade" : 87, "mean" : 100, "std" : 3 }, { "grade" : 85, "mean" : 100, "std" : 4 } ] }
Update All Array Elements that Match Multiple Conditions
Consider a collection students2 with the following documents:
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 100, "std" : 4 }, { "grade" : 85, "mean" : 100, "std" : 6 } ] } { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 100, "std" : 6 }, { "grade" : 87, "mean" : 100, "std" : 3 }, { "grade" : 85, "mean" : 100, "std" : 4 } ] }
To modify the value of the std field for all elements in the
grades array where both the grade is greater than or equal to
80 and the std is greater than or equal to 5, use the
positional $[<identifier>] operator and arrayFilters:
db.students2.updateMany( { }, { $inc: { "grades.$[elem].std" : -1 } }, { arrayFilters: [ { "elem.grade": { $gte: 80 }, "elem.std": { $gte: 5 } } ] } )
After the operation, the collection has the following documents:
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 5 }, { "grade" : 85, "mean" : 100, "std" : 4 }, { "grade" : 85, "mean" : 100, "std" : 5 } ] } { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 100, "std" : 5 }, { "grade" : 87, "mean" : 100, "std" : 3 }, { "grade" : 85, "mean" : 100, "std" : 4 } ] }
Update Array Elements Using a Negation Operator
Consider a collection alumni with the following documents:
{ "_id": 1, "name": "Christine Franklin", "degrees": [ { "level": "Master", "major": "Biology", "completion_year": 2010, "faculty": "Science" }, { "level": "Bachelor", "major": "Biology", "completion_year": 2008, "faculty": "Science" } ], "school_email": "cfranklin@example.edu", "email": "christine@example.com" } { "_id": 2, "name": "Reyansh Sengupta", "degrees": [ { "level": "Bachelor", "major": "Chemical Engineering", "completion_year": 2002, "faculty": "Engineering" } ], "school_email": "rsengupta2@example.edu" }
To modify all elements in the degrees array that do not have
"level": "Bachelor", use the positional $[<identifier>]
operation with the $ne query operator:
db.alumni.update( { }, { $set : { "degrees.$[degree].gradcampaign" : 1 } }, { arrayFilters : [ {"degree.level" : { $ne: "Bachelor" } } ], multi : true } )
After the operation, the collection has the following documents:
{ "_id" : 1, "name" : "Christine Franklin", "degrees" : [ { "level" : "Master", "major" : "Biology", "completion_year" : 2010, "faculty" : "Science", "gradcampaign" : 1 }, { "level" : "Bachelor", "major" : "Biology", "completion_year" : 2008, "faculty" : "Science" } ], "school_email" : "cfranklin@example.edu", "email" : "christine@example.com" } { "_id" : 2, "name" : "Reyansh Sengupta", "degrees" : [ { "level" : "Bachelor", "major" : "Chemical Engineering", "completion_year" : 2002, "faculty" : "Engineering" } ], "school_email" : "rsengupta2@example.edu" }
Update Nested Arrays in Conjunction with $[]
The $[<identifier>] filtered positional operator, in conjunction
with the $[] all positional operator, can be used to update
nested arrays.
Create a collection students3 with the following document:
db.students3.insert( { "_id" : 1, "grades" : [ { type: "quiz", questions: [ 10, 8, 5 ] }, { type: "quiz", questions: [ 8, 9, 6 ] }, { type: "hw", questions: [ 5, 4, 3 ] }, { type: "exam", questions: [ 25, 10, 23, 0 ] }, ] } )
The following updates the values that are greater than or equal to
8 in the nested grades.questions array if the associated
grades.type field is quiz.
db.students3.update( {}, { $inc: { "grades.$[t].questions.$[score]": 2 } }, { arrayFilters: [ { "t.type": "quiz" } , { "score": { $gte: 8 } } ], multi: true} )
Note
Don't add spaces around the array identifiers. If you use
grades.$[ t ].questions.$[ score ] in the previous example, the
example fails.
After the operation, the collection has the following document:
{ "_id" : 1, "grades" : [ { "type" : "quiz", "questions" : [ 12, 10, 5 ] }, { "type" : "quiz", "questions" : [ 10, 11, 6 ] }, { "type" : "hw", "questions" : [ 5, 4, 3 ] }, { "type" : "exam", "questions" : [ 25, 10, 23, 0 ] } ] }
To update all values that are greater than or equal to 8 in the
nested grades.questions array, regardless of type:
db.students3.update( {}, { $inc: { "grades.$[].questions.$[score]": 2 } }, { arrayFilters: [ { "score": { $gte: 8 } } ], multi: true} )