Reputation: 120
I have a collection of store products, where each document is a product that is associated with a store and their locations, in addition to the quantity of that product for that store. The document schema looks as follows:
Sample Doc :
{
product : 'Mobile Phone',
store : 'Electronics Store',
total_quantity : 5,
locations : [ { id: 'loc1', quantity: 3 }, { id: 'loc2', quantity: 2 } ]
}
I want to be able to remove a location from all the store products by the location id, while also updating the total quantity.
I know I can do this by getting each document and updating it, but this requires queries equal to the amount of the products that has that location. Hence, I was thinking of trying to achieve this by doing two queries:
The problem here is I do not know how to achieve the first step or if it is even possible. Any other suggestions are more than welcome.
Upvotes: 0
Views: 356
Reputation: 17915
As you can execute update-with-an-aggregation-pipeline in .update()
operations starting MongoDB version >= 4.2
, try below queries :
Query 1 :
This query re-creates total_quantity
field by subtracting locations.quantity
of particular element being removed from existing total_quantity
. Also re-creates locations
array without element which needs to be removed.
db.collection.updateMany({'locations.id': 'loc1'},
[
{ $addFields: { total_quantity: { $subtract: [ "$total_quantity", { $arrayElemAt: [ "$locations.quantity", { $indexOfArray: [ "$locations.id", "loc1" ] } ] } ] } } },
{ $addFields: { locations: { $filter: { input: "$locations", cond: { $ne: [ "$$this.id", "loc1" ] } } } } }
]
)
Test : Test aggregation pipeline here : mongoplayground
Query 2 :
This query first re-creates locations
array without element which needs to be removed & then iterates through leftover array locations.quantity
to sum-up all the quantity
values of all elements in locations
array to create total_quantity
field.
db.collection.updateMany({'locations.id': 'loc1'},
[
{ $addFields: { locations: { $filter: { input: "$locations", cond: { $ne: [ "$$this.id", "loc1" ] } } } } },
{ $addFields: { total_quantity: { $reduce: { input: "$locations.quantity", initialValue: 0, in: { $add: [ "$$value", "$$this" ] } } } } }
]
)
Test : Test aggregation pipeline here : mongoplayground
Note : If you find any issue executing these queries with .updateMany()
try .update()
with an option { multi : true }
.
Upvotes: 1