...
MongoDB Update is working inconsistently when using the positional $ operator to update an array element. It seems to be always updating the first element and not the element matching the query condition. Found that update is working as expected when the array element field name is changed from "s" to "a". Please see steps to reproduce for more details. Found the issue on MongoDB server version: 3.6.2. Not sure if it is present in all versions.
eric.sedor commented on Tue, 26 Feb 2019 22:22:30 +0000: Hi, thanks for writing in. $elemMatch should help you target specific array elements more accurately. For example, per this documentation the following should work: db.mycoll.update({ "_id" : 1, arr: {"$elemMatch": {"s": "ABC", "c":"12345"}}}, { "$set" : { "arr.$.s" : "ABC", "arr.$.c" : "12345", "arr.$.count" : 5 }}) For further questions about using specific MongoDB features, please post on the mongodb-user group or Stack Overflow with the mongodb tag.
Steps to reproduce the problem Steps to show changing field name makes it work as expected. Note the only change is array element field name is changed from "s" to "a" Tried on MongoDB server version: 3.6.2 Steps to reproduce the problem. // code placeholder > db.mycoll.insert({"_id":1, "arr":[{"s": "ABC", "c":"123", "count": 1}, {"s": "ABC", "c":"12345", "count": 2}]}) WriteResult({ "nInserted" : 1 }) > db.mycoll.find().pretty()> db.mycoll.find().pretty() { "_id" : 1, "arr" : [ { "s" : "ABC", "c" : "123", "count" : 1 }, { "s" : "ABC", "c" : "12345", "count" : 2 } ] } > db.mycoll.update({ "_id" : 1, "arr.s": "ABC", "arr.c":"12345"}, { "$set" : { "arr.$" : { "s" : "ABC", "c" : "12345", "count" : 5 }}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.mycoll.find().pretty() { "_id" : 1, "arr" : [ { "s" : "ABC", "c" : "12345", // *** wrong array element updated "count" : 5 // *** wrong array element updated }, { "s" : "ABC", "c" : "12345", "count" : 2 } ] } Steps to show changing field name makes it work as expected. Note the only change is array element field name is changed from "s" to "a" > db.mycoll.insert({"_id":1, "arr":[{"a": "ABC", "c":"123", "count": 1}, {"a": "ABC", "c":"12345", "count": 2}]}) WriteResult({ "nInserted" : 1 }) > db.mycoll.find().pretty() { "_id" : 1, "arr" : [ { "a" : "ABC", "c" : "123", "count" : 1 }, { "a" : "ABC", "c" : "12345", "count" : 2 } ] } > db.mycoll.update({ "_id" : 1, "arr.a": "ABC", "arr.c":"12345"}, { "$set" : { "arr.$" : { "a" : "ABC", "c" : "12345", "count" : 5 }}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.mycoll.find().pretty() { "_id" : 1, "arr" : [ { "a" : "ABC", "c" : "123", "count" : 1 }, { "a" : "ABC", "c" : "12345", // *** correctly updated "count" : 5 // *** correctly updated } ] }