Home > Net >  Overwrite value and create key while update query in mongodb
Overwrite value and create key while update query in mongodb

Time:04-22

I have a mongodb collection that looks like this:

{
     "_id" : ObjectId("60471bd482c0da3c0e70d26f"),
     "owner" : "John",
     "propAvailable" : {
        "val1" : true
    }
},
{
    "_id" : ObjectId("60471bd482c0da3c0e76523f"),
    "owner" : "Matt",
    "propAvailable" : {
    "val1" : {
       "val2" : true  
    }
}

I need to run an update query on this collection that will update the value of the 'propAvailable' key such that

>> db.collection('props').update({'owner' : 'John'} , {$set : {'propAvailable.val1.val2' : true}});

This query works if the document already looks like the second one but gives the error: Cannot create field 'val2' in element {'val1': true} if the document format is the first one. Is there a way to write this query so that it overwrites the boolean 'true' and replaces it with the object {'val2' : true}

CodePudding user response:

If you're using Mongo version 4.2 you can use pipelined updates to achieve this, like so:

db.collection.updateMany({
  owner: "John"
},
[
  {
    $set: {
      "propAvailable.val1": {
        $mergeObjects: [
          {
            $cond: [
              {
                $eq: [
                  "object",
                  {
                    $type: "$propAvailable.val1"
                  }
                ]
              },
              "$propAvailable.val1",
              {}
            ]
          },
          {
            val2: true
          }
        ]
      }
    }
  },
])

Mongo Playground

For older mongo versions this is impossible to do in 1 query if objects potentially have additional fields under val1 you want to preserve. You will have to either read and update, or execute two different updates for each case.

CodePudding user response:

You can use:

db.collection.update({
  "owner": "John"
},
{
  $set: {
    "propAvailable.val1": {
      val2: true
    }
  }
})

To create val2: true inside propAvailable.val1 and replace its current content.

As you can see working on the playground

  • Related