Home > front end >  Update all subdocuments of a sub-document (not an array)
Update all subdocuments of a sub-document (not an array)

Time:10-29

My documents are of the following format:

{ 
  _id: 'something',
  topLevelProp: 'top' 
  obj: { 
    prop1: { a: 'a', b: 'b' }, 
    prop2: { a: 'x', b: 'y'},
    prop3: {a: 'x'}
  }
}

I want to update all the subdocuments inside obj to include the value of topLevelProp.
So, the result would be:

{ 
  _id: 'something',
  topLevelProp: 'top' 
  obj: { 
    prop1: { a: 'a', b: 'b', anotherProp: 'top' }, 
    prop2: { a: 'x', b: 'y', anotherProp: 'top'},
    prop3: {a: 'x', anotherProp: 'top'}
  }
}

The closest I could get was something like
db.update({_id: "something")}, {$set: {'obj.$.anotherProp': '$topLevelProp'}}) which doesn't actually work, giving this write error: Cannot apply array updates to non-array element obj.
Guess this is because $ is meant for use in arrays, not objects. using $[] produces similar error, as expected.

Is there a way to do something like this?

CodePudding user response:

Use $objectToArray to convert obj into array of k-v tuples. $mergeObjects to add the key. Finally use $arrayToObject to revert back to original object form.

db.collection.update({},
[
  {
    "$addFields": {
      "obj": {
        "$objectToArray": "$obj"
      }
    }
  },
  {
    "$addFields": {
      "obj": {
        "$map": {
          "input": "$obj",
          "as": "o",
          "in": {
            k: "$$o.k",
            v: {
              "$mergeObjects": [
                "$$o.v",
                {
                  anotherProp: "$topLevelProp"
                }
              ]
            }
          }
        }
      }
    }
  },
  {
    "$addFields": {
      "obj": {
        "$arrayToObject": "$obj"
      }
    }
  }
],
{
  multi: true
})

Mongo Playground

  • Related