Home > OS >  How to map on array fields with a dynamic variable in MongoDB, while projection (aggregation)
How to map on array fields with a dynamic variable in MongoDB, while projection (aggregation)

Time:11-23

I want to serve data from multiple collections, let's say product1 and product2.
Schemas of both can be referred to as -:

{ amount: Number }  // other fields might be there but not useful in this case.

Now after multiple stages of aggregation pipeline, I'm able to get the data in the following format-:

items: [
  {
    amount: 10,
    type: "product1",
    date: "2022-10-05"
  },
  {
    amount: 15,
    type: "product2",
    date: "2022-10-07"
  },
  {
    amount: 100,
    type: "product1",
    date: "2022-10-10"
  }
 ]

However, I want one more field added to each element of items - The sum of all the previous amounts.

Desired Result -:

items: [
  {
    amount: 10,
    type: "product1",
    date: "2022-10-05",
    totalAmount: 10
  },
  {
    amount: 15,
    type: "product2",
    date: "2022-10-07",
    totalAmount: 25
  },
  {
    amount: 100,
    type: "product1",
    date: "2022-10-10",
    totalAmount: 125
  }
 ]

I tried adding another $project stage, which goes as follows -:

{
  
  items: {
    $map: {
      input: "$items",
      in: {
        $mergeObjects: [
          "$$this",
          { totalAmount: {$add : ["$$this.amount", 0] } },
          ]
      }
    }
  }
}

This just appends another field, totalAmount as the sum of 0 and the amount of that item itself.

I couldn't find a way to make the second argument (currently 0) in {$add : ["$$this.amount", 0] } as a variable (initial value 0).

What's the way to perform such action in MongoDb aggregation pipeline ?

PS-: I could easily perform this action by a later mapping in the code itself, but I need to add limit (for pagination) to it in the later stage.

CodePudding user response:

You can use $reduce instead of $map for this:

db.collection.aggregate([
  {$project: {
      items: {
        $reduce: {
          input: "$items",
          initialValue: [],
          in: {
            $concatArrays: [
              "$$value",
              [{$mergeObjects: [
                  "$$this",
                  {totalAmount: {$add: ["$$this.amount", {$sum: "$$value.amount"}]}}
              ]}]
            ]
          }
        }
      }
  }}
])

See how it works on the playground example

  • Related