You can also try using the positional $ operator used with findAndModify() . The operator will identify the element in the array for updating without explicitly specifying the position of the element in the array. Please note: the array field should be displayed as part of the request document and return the document with the changes made to the update, use the new parameter, so your update will look like
db.tests.findAndModify({ query: { "arr.cond": 4 }, update: { "$set": {"arr.$.upd": 55 } }, new : true, fields: { "arr": 1, "_id": 0 } })
will produce output:
{ "arr": [ { "cond" : 1, "upd" : 2 }, { "cond" : 2, "upd" : 3 }, { "cond" : 4, "upd" : 55 }, { "cond" : 6, "upd" : 7 }, { "cond" : 8, "upd" : 9 } ] }
Since you want to return an updated document, the positional $ projection operator in the projection document of the find() or findOne() method can be used with the projection, so findAndModify() field will not project this part of the array using the $ projection operator.
A workaround would be to use your own JavaScript filter() method in the returned arr field as
var result = db.tests.findAndModify({ query: { "arr.cond": 4 }, update: { "$set": {"arr.$.upd": 55 } }, new : true, fields: { "arr": 1, "_id": 0 } }) var updated = [] if (result && result.arr) updated = result.arr.filter(function (item) { return item.cond == 4; }); printjson(updated);
Will open
[ { "cond" : 4, "upd" : 55 } ]
- UPDATE -
Or the $elemMatch projection, as you suggested in the comments below:
var result = db.tests.findAndModify({ query: { "arr.cond": 4 }, update: { "$set": {"arr.$.upd": 55 } }, new : true, fields: {"arr": {"$elemMatch": { "cond": 4 } }, "_id": 0 } }) printjson(result);
Output
{ "arr" : [ { "cond" : 4, "upd" : 55 } ] }