Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Mongo array update $elemMatch and $in operator miss behaving based on data

I’m trying to update an object in an array using the $elemMatch AND the $in operator on another array field.

My query looks like this:

    var query = {array:{$in: ['second']},objectList: {$elemMatch: {toMatch: {$exists: true}}} };
db.foo.update(query, {$set: {'objectList.$.toChange':10}}, {multi: true})

If array is ["second","first"] the update operation will update the object as expected.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

If array is ["first","second"] the update operation will append a new object in objectList instead of doing an update.

How to reproduce:

db.foo.insert({ "objectList" : [{"toChange" : 0.0,"toMatch" : "bar"}],"array" : ["first","second"] })
db.foo.insert({ "objectList" : [{"toChange" : 0.0,"toMatch" : "bar"}],"array" : ["second","first"] })

var query = {array:{$in: ['second']},objectList: {$elemMatch: {toMatch: {$exists: true}}} }
db.foo.update(query, {$set: {'objectList.$.toChange':10}}, {multi: true})
db.foo.find(query, {_id:0})

Returns:

{
    "objectList" : [ 
        {
            "toChange" : 0.0,
            "toMatch" : "bar"
        }, 
        {
            "toChange" : 10.0
        }
    ],
    "array" : [ 
        "first", 
        "second"
    ]
},
{
    "objectList" : [ 
        {
            "toChange" : 10.0,
            "toMatch" : "bar"
        }
    ],
    "array" : [ 
        "second", 
        "first"
    ]
}

This has been tested on mongo db versions:
db.version() => 5.0.3
db.version() => 4.2.18
db.version() => 4.4.11

>Solution :

This one is working correctly:

db.collection.update({
   array: {
    $in: [
      "second"
    ]
  },
  objectList: {
    $elemMatch: {
      toMatch: {
        $exists: true
      }
    }
  }
},
{
  $set: {
    "objectList.$[].toChange": 10
  }
},
{
  multi: true
})

playground

Explained:
The $ need to be $[] , also $arrayFilters can be used here as well
but indeed it is an iteresting buggy behaviour of $

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading