querydrill

Learn ›Aggregation ›Grouping and accumulators

Grouping by more than one field

$group$sum

Grouping by two fields is just an object as the _id. The part that catches people is the output: your grouping key is now nested inside _id, so every later stage has to reach through it.

Suppose:

Find quantity sold per user per product.

You can group by an object.

{
  $group: {
    _id: {
      userId: "$userId",
      product: "$items.product"
    },

    quantity: {
      $sum: "$items.quantity"
    }
  }
}

Result:

{
  _id: {
    userId: 101,
    product: "Laptop"
  },

  quantity: 1
}

This is equivalent conceptually to:

GROUP BY userId, product

The $group _id Is Just the Grouping Key

This confuses many people initially.

Here:

{
  $group: {
    _id: "$userId"
  }
}

_id does not mean the original document ID.

Inside $group:

_id means “what am I grouping by?”

Examples:

_id: "$userId"

Group by user.

_id: "$items.product"

Group by product.

_id: null

Everything goes into one group.

Example:

{
  $group: {
    _id: null,

    totalRevenue: {
      $sum: "$amount"
    }
  }
}

Result:

{
  _id: null,
  totalRevenue: 50000
}

Meaning:

Calculate one total across all documents.

This is a common interview pattern.

Try it

db.orders.aggregate([
  { $unwind: "$items" },
  {
    $group: {
      _id: {
        userId: "$userId",
        product: "$items.product"
      },
      quantity: { $sum: "$items.quantity" }
    }
  },
  { $sort: { quantity: -1 } },
  { $limit: 5 }
])

Look at the shape of _id in the output. If you wanted to sort by user next, the field is _id.userId, not userId - that is the cost of the compound key.

Practise this

1 exercise