Search code examples
javascriptnode.jsmongodbmongooseaggregation-framework

mongodb aggregation $sum returning 0 instead of actual sum of integers in array


My document looks like this:

{
  "_id": "2023-04-08",
  "dailyNotes": [
    {
      "therapyDiscipline": "PT",
      "individual": [
        60,
        45,
        30,
        75,
        55
      ],
      "concurrent": [
        69
      ],
      "coTreat": [
        67
      ]
    }
  ]
}

I want to sum all numbers inside individual array and create a new doc with only individual key having the sum of array.

Here's what I have tried so far but didn't work

{
$group: 
{
  _id: '$_id',
  individual:{
    $sum: '$dailyNotes.individual'
  }
}
}

this returns:

{
  "_id": "2023-04-08",
  "individual": 0
}

I don't understand why this is returning 0, instead it should have returned 265.

few other solutions I tried but they also resulted in 0 sum:

{
$project: {
  individual: {
    $reduce: {
        input: "$dailyNotes.individual", 
        initialValue: 0,
        in: { $sum: [ "$$value", "$$this" ]}
    }
  }
}
}
{
$project: 
{
  individual: {
    $sum: '$dailyNotes.individual'
  }
}
}

Can someone explains why its returning 0 instead of the 265 and how to fix this?

[Update]: (example with multiple(max 3) records) For a document like:

{
   "_id":"2023-04-08",
   "dailyNotes":[
      {
         "therapyDiscipline":"PT",
         "individual":[
            60,
            45,
            30,
            75,
            55
         ]
      },
      {
         "therapyDiscipline":"YT",
         "individual":[
            2,
            4
         ]
      }
   ]
}

this should return as:

{
   "_id":"2023-04-08",
   "dailyNotes":[
      {
         "individual":265
      },
      {
         "individual":6
      }
   ]
}

Solution

  • the easiest way you can achieve this is using a $map along with $sum

    db.collection.aggregate([
      {
        $project: {
          _id: 1,
          dailyNotes: {
            $map: {
              input: "$dailyNotes",
              in: { individual: { $sum: "$$this.individual" } }
            }
          }
        }
      }
    ])
    

    playground

    an alternative using $reduce

    db.collection.aggregate([
      {
        $project: {
          _id: 1,
          dailyNotes: {
            $reduce: {
              input: "$dailyNotes",
              initialValue: [],
              in: { $concatArrays: [ "$$value", [ { individual: { $sum: "$$this.individual" } } ] ] }
            }
          }
        }
      }
    ])
    

    playground