Fayad
Fayad

Reputation: 120

Decrement a field in mongodb using a field from the same document

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

Answers (1)

whoami - fakeFaceTrueSoul
whoami - fakeFaceTrueSoul

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

Related Questions