Home > Software engineering >  Mongo array update $elemMatch and $in operator miss behaving based on data
Mongo array update $elemMatch and $in operator miss behaving based on data

Time:01-15

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.

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

CodePudding user response:

This one is working correctly:

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

playground with elemMatch

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

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

playground with arrayFilters

  •  Tags:  
  • Related