$[<identifier>]

Definition

  • $[<identifier>]

New in version 3.6.

The filtered positional operator $[<identifier>] identifies thearray elements that match the arrayFilters conditions foran update operation, e.g. db.collection.update() anddb.collection.findAndModify().

Used in conjunction with the arrayFilters option, the$[<identifier>] operator has the following form:

  1. { <update operator>: { "<array>.$[<identifier>]" : value } },
  2. { arrayFilters: [ { <identifier>: <condition> } ] }

Use in conjunction with the arrayFilters option to update allelements that match the arrayFilters conditions in thedocument or documents that match the query conditions. For example:

  1. db.collection.updateMany(
  2. { <query conditions> },
  3. { <update operator>: { "<array>.$[<identifier>]" : value } },
  4. { arrayFilters: [ { <identifier>: <condition> } ] }
  5. )

Note

The <identifier> must begin with a lowercase letter andcontain only alphanumeric characters.

For an example, see Update All Array Elements That Match arrayFilters.

Behavior

upsert

If an upsert operation results in an insert, the query mustinclude an exact equality match on the arrayfield 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 conditionon the array field:

  1. db.collection.update(
  2. { myArray: [ 0, 1 ] },
  3. { $set: { "myArray.$[element]": 2 } },
  4. { arrayFilters: [ { element: 0 } ],
  5. upsert: true }
  6. )

If no such document exists, the operation would result in an insert ofa document that resembles the following:

  1. { "_id" : ObjectId(...), "myArray" : [ 2, 1 ] }

If the upsert operation did not include an exact equality match and nomatching documents were found to update, the upsert operation woulderror. For example, the following operations would errorif no matching documents were found to update:

  1. db.array.update(
  2. { },
  3. { $set: { "myArray.$[element]": 10 } },
  4. { arrayFilters: [ { element: 9 } ],
  5. upsert: true }
  6. )

The operation would return an error that resembles the following:

  1. WriteResult({
  2. "nMatched" : 0,
  3. "nUpserted" : 0,
  4. "nModified" : 0,
  5. "writeError" : {
  6. "code" : 2,
  7. "errmsg" : "The path 'myArray' must exist in the document in order to apply array updates."
  8. }
  9. })

Nested Arrays

The filtered positional operator $[<identifier>] canbe 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:

  1. { "_id" : 1, "grades" : [ 95, 92, 90 ] }
  2. { "_id" : 2, "grades" : [ 98, 100, 102 ] }
  3. { "_id" : 3, "grades" : [ 95, 110, 100 ] }

To update all elements that are greater than or equal to 100 in thegrades array, use the filtered positional operator$[<identifier>] with the arrayFilters:

  1. db.students.update(
  2. { },
  3. { $set: { "grades.$[element]" : 100 } },
  4. { multi: true,
  5. arrayFilters: [ { "element": { $gte: 100 } } ]
  6. }
  7. )

The positional $[<identifier>] operator acts as aplaceholder for all elements in the array field that match theconditions specified in arrayFilters.

After the operation, the students collection contains the followingdocuments:

  1. { "_id" : 1, "grades" : [ 95, 92, 90 ] }
  2. { "_id" : 2, "grades" : [ 98, 100, 100 ] }
  3. { "_id" : 3, "grades" : [ 95, 100, 100 ] }

Update All Documents That Match arrayFilters in an Array

The $[<identifier>] operator facilitates updates to arraysthat contain embedded documents. To access the fieldsin the embedded documents, use the dot notation on the $[<identifier>].

  1. db.collection.update(
  2. { <query selector> },
  3. { <update operator>: { "array.$[<identifier>].field" : value } },
  4. { arrayFilters: [ { <identifier>: <condition> } } ] }
  5. )

Consider a collection students2 with the following documents:

  1. {
  2. "_id" : 1,
  3. "grades" : [
  4. { "grade" : 80, "mean" : 75, "std" : 6 },
  5. { "grade" : 85, "mean" : 90, "std" : 4 },
  6. { "grade" : 85, "mean" : 85, "std" : 6 }
  7. ]
  8. }
  9. {
  10. "_id" : 2,
  11. "grades" : [
  12. { "grade" : 90, "mean" : 75, "std" : 6 },
  13. { "grade" : 87, "mean" : 90, "std" : 3 },
  14. { "grade" : 85, "mean" : 85, "std" : 4 }
  15. ]
  16. }

To modify the value of the mean field for all elements in thegrades array where the grade is greater than or equal to 85,use the positional $[<identifier>] operator andarrayFilters:

  1. db.students2.update(
  2. { },
  3. { $set: { "grades.$[elem].mean" : 100 } },
  4. {
  5. multi: true,
  6. arrayFilters: [ { "elem.grade": { $gte: 85 } } ]
  7. }
  8. )

After the operation, the collection has the following documents:

  1. {
  2. "_id" : 1,
  3. "grades" : [
  4. { "grade" : 80, "mean" : 75, "std" : 6 },
  5. { "grade" : 85, "mean" : 100, "std" : 4 },
  6. { "grade" : 85, "mean" : 100, "std" : 6 }
  7. ]
  8. }
  9. {
  10. "_id" : 2,
  11. "grades" : [
  12. { "grade" : 90, "mean" : 100, "std" : 6 },
  13. { "grade" : 87, "mean" : 100, "std" : 3 },
  14. { "grade" : 85, "mean" : 100, "std" : 4 }
  15. ]
  16. }

Update All Array Elements that Match Multiple Conditions

Consider a collection students2 with the following documents:

  1. {
  2. "_id" : 1,
  3. "grades" : [
  4. { "grade" : 80, "mean" : 75, "std" : 6 },
  5. { "grade" : 85, "mean" : 100, "std" : 4 },
  6. { "grade" : 85, "mean" : 100, "std" : 6 }
  7. ]
  8. }
  9. {
  10. "_id" : 2,
  11. "grades" : [
  12. { "grade" : 90, "mean" : 100, "std" : 6 },
  13. { "grade" : 87, "mean" : 100, "std" : 3 },
  14. { "grade" : 85, "mean" : 100, "std" : 4 }
  15. ]
  16. }

To modify the value of the std field for all elements in thegrades array where both the grade is greater than or equal to80 and the std is greater than or equal to 5, use thepositional $[<identifier>] operator and arrayFilters:

  1. db.students2.update(
  2. { },
  3. { $inc: { "grades.$[elem].std" : -1 } },
  4. { arrayFilters: [ { "elem.grade": { $gte: 80 }, "elem.std": { $gt: 5 } } ], multi: true }
  5. )

After the operation, the collection has the following documents:

  1. { "_id" : 1,
  2. "grades" : [
  3. { "grade" : 80, "mean" : 75, "std" : 5 },
  4. { "grade" : 85, "mean" : 100, "std" : 4 },
  5. { "grade" : 85, "mean" : 100, "std" : 5 }
  6. ]
  7. }
  8. {
  9. "_id" : 2,
  10. "grades" : [
  11. { "grade" : 90, "mean" : 100, "std" : 5 },
  12. { "grade" : 87, "mean" : 100, "std" : 3 },
  13. { "grade" : 85, "mean" : 100, "std" : 4 }
  14. ]
  15. }

Update Array Elements Using a Negation Operator

Consider a collection alumni with the following documents:

  1. {
  2. "_id": 1,
  3. "name": "Christine Franklin",
  4. "degrees": [
  5. { "level": "Master",
  6. "major": "Biology",
  7. "completion_year": 2010,
  8. "faculty": "Science"
  9. },
  10. {
  11. "level": "Bachelor",
  12. "major": "Biology",
  13. "completion_year": 2008,
  14. "faculty": "Science"
  15. }
  16. ],
  17. "school_email": "cfranklin@example.edu",
  18. "email": "christine@example.com"
  19. }
  20. {
  21. "_id": 2,
  22. "name": "Reyansh Sengupta",
  23. "degrees": [
  24. { "level": "Bachelor",
  25. "major": "Chemical Engineering",
  26. "completion_year": 2002,
  27. "faculty": "Engineering"
  28. }
  29. ],
  30. "school_email": "rsengupta2@example.edu"
  31. }

To modify all elements in the degrees array that do not have"level": "Bachelor", use the positional [<identifier>]operation with the $ne query operator:

  1. db.alumni.update(
  2. { },
  3. { $set : { "degrees.$[degree].gradcampaign" : 1 } },
  4. { arrayFilters : [ {"degree.level" : { $ne: "Bachelor" } } ],
  5. multi : true }
  6. )

After the operation, the collection has the following documents:

  1. {
  2. "_id" : 1,
  3. "name" : "Christine Franklin",
  4. "degrees" : [
  5. {
  6. "level" : "Master",
  7. "major" : "Biology",
  8. "completion_year" : 2010,
  9. "faculty" : "Science",
  10. "gradcampaign" : 1
  11. },
  12. {
  13. "level" : "Bachelor",
  14. "major" : "Biology",
  15. "completion_year" : 2008,
  16. "faculty" : "Science"
  17. }
  18. ],
  19. "school_email" : "cfranklin@example.edu",
  20. "email" : "christine@example.com"
  21. }
  22. {
  23. "_id" : 2,
  24. "name" : "Reyansh Sengupta",
  25. "degrees" : [
  26. {
  27. "level" : "Bachelor",
  28. "major" : "Chemical Engineering",
  29. "completion_year" : 2002,
  30. "faculty" : "Engineering"
  31. }
  32. ],
  33. "school_email" : "rsengupta2@example.edu"
  34. }

Update Nested Arrays in Conjunction with $[]

The $[<identifier>] filtered positional operator, in conjunctionwith the $[] all positional operator, can be used to updatenested arrays.

Create a collection students3 with the following document:

  1. db.students3.insert(
  2. { "_id" : 1,
  3. "grades" : [
  4. { type: "quiz", questions: [ 10, 8, 5 ] },
  5. { type: "quiz", questions: [ 8, 9, 6 ] },
  6. { type: "hw", questions: [ 5, 4, 3 ] },
  7. { type: "exam", questions: [ 25, 10, 23, 0 ] },
  8.  
  9. ]
  10. }
  11. )

The following updates the values that are greater than or equal to8 in the nested grades.questions array if the associatedgrades.type field is quiz.

  1. db.students3.update(
  2. {},
  3. { $inc: { "grades.$[t].questions.$[score]": 2 } },
  4. { arrayFilters: [ { "t.type": "quiz" } , { "score": { $gte: 8 } } ], multi: true}
  5. )

After the operation, the collection has the following document:

  1. {
  2. "_id" : 1,
  3. "grades" : [
  4. { "type" : "quiz", "questions" : [ 12, 10, 5 ] },
  5. { "type" : "quiz", "questions" : [ 10, 11, 6 ] },
  6. { "type" : "hw", "questions" : [ 5, 4, 3 ] },
  7. { "type" : "exam", "questions" : [ 25, 10, 23, 0 ] }
  8. ]
  9. }

To update all values that are greater than or equal to 8 in thenested grades.questions array, regardless of type:

  1. db.students3.update(
  2. {},
  3. { $inc: { "grades.$[].questions.$[score]": 2 } },
  4. { arrayFilters: [ { "score": { $gte: 8 } } ], multi: true}
  5. )

See also