8. Grouping Documents with $group

$group combines documents with the same _id group key and calculates values with accumulators. Use _id: null to create one overall summary, or a field or constructed document to group by one or multiple dimensions.

Common accumulators include $sum, $avg, $min, $max, $first, $last, $push, $addToSet, $stdDevPop, and $stdDevSamp. $first and $last depend on input order; sort first if chronological order matters.

Grouping can be expensive when many distinct keys are created. Be cautious about collecting very large arrays with $push, especially because result documents must remain within BSON size limits.

The group key defines the result

Grouping by customer produces customer summaries; grouping by status produces status summaries; grouping by both produces one summary for each combination.

Code Example
db.orders.aggregate([
  { $match: { status: "delivered" } },
  {
    $set: {
      itemSubtotal: {
        $sum: {
          $map: {
            input: "$items",
            as: "item",
            in: { $multiply: ["$$item.quantity", "$$item.price"] }
          }
        }
      }
    }
  },
  {
    $group: {
      _id: "$customerId",
      deliveredOrderCount: { $sum: 1 },
      totalItemRevenue: { $sum: "$itemSubtotal" },
      averageOrderSubtotal: { $avg: "$itemSubtotal" },
      lowestOrderSubtotal: { $min: "$itemSubtotal" },
      highestOrderSubtotal: { $max: "$itemSubtotal" }
    }
  },
  { $sort: { totalItemRevenue: -1, _id: 1 } }
]);
Key Takeaways
  • $group requires an _id key.
  • Use _id: null for one overall summary.
  • Accumulators calculate totals and summaries.
  • Sort explicitly when $first or $last must be chronological.
Knowledge Check

Which configuration calculates one total across all input documents?