Home > Back-end >  Combine arrays in MongoDB $group aggregation
Combine arrays in MongoDB $group aggregation

Time:11-28

I am using Mongo daily bucketing pattern. Each daily document contains an array with value calculated for every hour for that day:

{
  meter: 'meterId',
  date: 'dailyBucket',
  hourlyConsumption: [0,0,1,1,1,2,2,2,4,4,4,4,3,3,3...] // array with 24 values for every hour of a day
}

Now in one of my aggregation queries, I would like to group documents for the same day of multiple meters and get a result like this:

INPUT (consumption of multiple meters in a same day)

{
  meter: 'MeterA',
  date: '2021-05-01',
  hourlyConsumption: [0,0,1,1,1,2,2,2,4,4,4,4,3,3,3...]
},
{
  meter: 'MeterB',
  date: '2021-05-01',
  hourlyConsumption: [10,10,10,10,10,10,10,10,10,10,10,10,10,10,10...]
}

RESULT (combined into single document)

{
  date: '2021-05-01',
  hourlyConsumption: [10,10,11,11,11,12,12,12,14,14,14,14,13,13,13...]
}

is there a way to achieve this without using $accumulator?

CodePudding user response:

You can use $reduce

db.collection.aggregate([
  {
    $group: {
      _id: "$date",
      hourlyConsumption: { $push: "$hourlyConsumption" }
    }
  },
  {
    $set: {
      hourlyConsumption: {
        $reduce: {
          input: "$hourlyConsumption",
          initialValue: [],
          in: { $map: { input: { $range: [ 0, 23 ] },
              as: "h",
              in: {
                $sum: [ 
                  { $arrayElemAt: [ "$$value", "$$h" ] },
                  { $arrayElemAt: [ "$$this", "$$h" ] }
                ]
              }
            }
          }
        }
      }
    }
  }
])

Mongo Playground

Or you use $unwind and $group:

db.collection.aggregate([
  {
    $unwind: {
      path: "$hourlyConsumption",
      includeArrayIndex: "hour"
    }
  },
  {
    $group: {
      _id: {
        date: "$date",
        hour: "$hour"
      },
      hourlyConsumption: { $sum: "$hourlyConsumption" }
    }
  },
  { $sort: { "_id.hour": 1 } },
  {
    $group: {
      _id: "$_id.date",
      hourlyConsumption: { $push: "$hourlyConsumption" }
    }
  }
])

Mongo Playground

However, when you use $unwind, then you actually contradict your bucketing design pattern.

  • Related