'Overwrite value and create key while update query in mongodb

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}



Solution 1:[1]

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

Solution 2:[2]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Tom Slabbaert