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
})