简体   繁体   中英

Update multiple properties in array of objects with MongoDb

I have an array of objects like this:

vale { 
  cantidad: 23
  historial {
    entradas:[
             {cantidad: 5}, 
             {cantidad:10}, 
             {cantidad:8}
           ]
    salidas:[]
          } 
}

I want to make a mongo query that given a certain "cantidad" it will substract it from the "entradas array"

for example if I want to substract 7 at the end the object will look like this:

vale { 
  cantidad: 16
  historial {
    entradas:[
             {cantidad: 0}, 
             {cantidad: 8}, 
             {cantidad:8}
           ]
    salidas:[]
          } 
}

So now cantidad is 16 and the "entradas" array put the first one in "0" and then substract the remaing value to the next one, if I would have substracted 17 then the entradas array should look like this:

  entradas:[
             {cantidad: 0}, 
             {cantidad: 0}, 
             {cantidad:6}
           ]

The process should be like: 
value = 17
(entradas[0] - value < 0) --> true
then
value -= entradas[0]; entradas[0] = 0 --> value is now 12
then
(entradas[1] - value < 0) --> true
then
value -= entradas[1]; entradas[1] = 0 --> value is now 2
then
(entradas[2] - value < 0) --> false
then
entradas[2] -= value --> value is now 0

Im trying to learn advanced queries of mongoDb but to be honest I have no idea how to this or if its even possible in a MongoDb query. The "cantidad" and the sum of all "entradas.cantidad" will always be the same and I make sure to validate that the value is less than the total quantity before making this update.

Hope that someone can help me out:)

This is one way of doing it using an aggregation pipeline, although it's better that you fetch the document, first, modify it in the application, and then update it. If you wanna do it via MongoDB only, try this:

db.collection.aggregate([
  {
    "$match": {
      cantidad: 23
    }
  },
  {
    "$addFields": {
      "newDoc": {
        "$function": {
          "body": "function(data, value) { data.cantidad = data.cantidad - value; data.historial.entradas = data.historial.entradas.map(entrada => { let copy = entrada.cantidad; entrada.cantidad = Math.max(entrada.cantidad-value, 0); value = Math.max(value - copy, 0); return entrada; }); return data; }",
          "args": [
            "$$ROOT",
            7
          ],
          "lang": "js"
        }
      }
    }
  },
  {
    "$replaceRoot": {
      "newRoot": "$newDoc"
    }
  },
  {
    "$merge": {
      "into": "collection",
      "on": "_id",
      "whenMatched": "replace",
      
    }
  }
])

Here's the playground link .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM