I have a collection that contains objects such as this.
{
materials: {
"m1": {
inventory: [
{
price: 100,
amount: 65
}
]
}
}
}
As you can see inventory is an array deep inside the hierarchy. I want to update the amount
field of it.
From the client I receive the material id ("m1"
) and the inventory index (0
).
I have to use an update pipeline because I am setting and unsetting some other fields in this document.
This is what I tried:
await products.findOneAndUpdate(filters, [
{
$set: {
"materials.m1.inventory.0.amount": 100,
},
},
]);
But it creates a new field named 0 inside the 0th element and sets the amount
inside that object. So the resulting document looks like this.
{
materials: {
"m1": {
inventory: [
{
0: {
amount: 100
}
price: 100,
amount: 65
}
]
}
}
}
Whereas what I want is this:
{
materials: {
"m1": {
inventory: [
{
price: 100,
amount: 100
}
]
}
}
}
The only way for me to identify which element in the array to update is the index of it.
I am using nodejs mongodb driver. How to write the $set
stage for this update pipeline?
I don't think any other straightway to update the specific index position element using aggregation pipeline,
$range
to generate array from 0 to length of materials.m1.inventory
array$map
to iterate loop of above range array$cond
to check current element is 0 then go to update part otherwise return element from materials.m1.inventory
by input index$arrayElemAt
to get specific element from materials.m1.inventory
$mergeObjects
to merge current object with amount
updated propertyawait products.findOneAndUpdate(filters, [
{
$set: {
"materials.m1.inventory": {
$map: {
input: {
$range: [0, { $size: "$materials.m1.inventory" }]
},
in: {
$cond: [
{ $eq: ["$$this", 0] }, // 0 position
{
$mergeObjects: [
{ $arrayElemAt: ["$materials.m1.inventory", "$$this"] },
{ amount: 100 } // input amount
]
},
{ $arrayElemAt: ["$materials.m1.inventory", "$$this"] }
]
}
}
}
}
}
]);