Let's say I have a schema in this format:
const some_schema = new mongoose.Schema({
"id": { type: Number },
"list": [
{
id: { type: Number },
value: { type: Number }
}
]
})
I need to update multiple objects in the list
using arrayFilters
given that every key in the arrayFilters
is unique and will only match 1 object in the list
.
I can make dynamic keys using JS like so:
//original doc values:
{
"id": 10,
"list": [
{ id: 1, value: 5 },
{ id: 2, value: 10 }
]
}
let updates = [ { id: 1, newValue: 10 }, { id: 2, newValue: 20 }];
let queryOptions = { arrayFilters: [] }, queryUpdates = { $set: {} };
for (const key in updates) {
queryOptions.arrayFilters.push({ [`${key}`]: key });
queryUpdates.$set[[`elem.$[${key}].value`]] = updates[key].newValue;
}
//update query
await doc.updateOne(queryUpdates, queryOptions);
//updated doc values:
{
"id": 10,
"list": [
{ id: 1, value: 10 },
{ id: 2, value: 20 }
]
}
Is there some way to do this directly in arrayFilters
or some other method in MongoDB without having to make dynamic keys like the above?
You may work on the update with the aggregation pipeline.
$let
- Declare the variable(s) withupdates
array.1.1.
$map
- Iterate each element in thelist
array.1.1.1.
$mergeObjects
- Merge the current iterated element (ori
) with the result from 1.1.1.1. If the result does exist, the current iterated element's fields will be updated. Otherwise, it remains as the original.1.1.1.1.
$first
&$filter
- Get the first matching element from thenewList
by matchingid
.Note that the objects in the
updates
array are required to have the same field name as in your document in order to update (overwrite) the value.Demo @ Mongo Playground