You need to add a $where
condition to the query portion of the statment in order to make sure that the document contains the array match in the "last" position. But that's only an "additional" constraint, and the "position" should be obtained from the standard query option of "steps.name": "name2"
:
So given sample documents:
/* 1 */
{
"_id" : ObjectId("59c39cf859f55d64d6e30293"),
"container_id" : 12.0,
"steps" : [
{
"name" : "name1"
},
{
"name" : "name2"
}
]
}
/* 2 */
{
"_id" : ObjectId("59c39d1b59f55d64d6e30294"),
"container_id" : 12.0,
"steps" : [
{
"name" : "name1"
},
{
"name" : "name2"
},
{
"name" : "name3"
}
]
}
Issuing the query:
db.collection('junk').update(
{
"container_id": 12,
"steps.name": "name2",
"$where": "this.steps.slice(-1)[0].name === 'name2'"
},
{ "$set": { "steps.$.name": "new name4" } },
{ "multi": true }
)
Results in:
/* 1 */
{
"_id" : ObjectId("59c39cf859f55d64d6e30293"),
"container_id" : 12.0,
"steps" : [
{
"name" : "name1"
},
{
"name" : "new name4"
}
]
}
/* 2 */
{
"_id" : ObjectId("59c39d1b59f55d64d6e30294"),
"container_id" : 12.0,
"steps" : [
{
"name" : "name1"
},
{
"name" : "name2"
},
{
"name" : "name3"
}
]
}
So the second document though containing an array element with the matching value of "name2"
, gets excluded by the $where
clause since it's not the last element in the array.
Only the first document gets updated because it matched both of the conditions.
NOTE: You still need the "steps.name": "name2"
in the query portion of .update()
in order to give the position for the positional $
operator. If there are actually more than one match in the array for the same value, then it's not possible to do at this time. See How to Update Multiple Array Elements in MongoDB for more detail on multiple matches.