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?
>Solution :
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
})