$sum
Add numeric values in the group
{ $sum: "$amount" } 
MongoDB accumulators are operators that compute one result per group. They live mainly inside the $group stage and roll many documents into totals, averages, arrays, or ranked picks.
You use accumulators to sum, average, collect, rank, and merge values across documents that share the same group key. Expression operators (like $add) work on one document at a time; accumulators work across a whole bucket.
Accumulator = rollup inside $group
Examples:
$sum → total (or count with $sum: 1)
$avg → mean of numeric values
$push → collect every value into an array
$topN → top N ranked documents per group
Browse every tutorial in the left sidebar. Documents enter $group. MongoDB puts each document into a bucket based on _id. Every accumulator field updates its state for that bucket, then emits one value when the group finishes.
$match._id (field, compound object, or null).$sum, $avg, …).| Piece | Role |
|---|---|
_id | Defines the group bucket (field, object, or null) |
| Accumulator field | One output value (or array) per bucket |
| Field path | "$amount" reads the current document’s field |
| Input order | Matters for $first / $last—sort first when needed |
// Total + count per store
db.orders.aggregate([
{
$group: {
_id: "$storeId",
revenue: { $sum: "$amount" },
orders: { $sum: 1 }
}
}
])
// Global average (one bucket)
db.orders.aggregate([
{ $group: { _id: null, avgAmount: { $avg: "$amount" } } }
]) _id: "$storeId" creates one group per store.$sum: adds amount; $sum: 1 counts documents._id: null puts every document in one bucket for a single average.Accumulators appear as fields inside $group. The pattern is always: output field name → { $accumulator: <input> }.
{
$group: {
_id: <group key>,
<outputField>: { $accumulatorName: <expression> }
}
}
"$fieldName" → value from the current document
$sum: 1 → count documents in the group $sumAdd numeric values in the group
{ $sum: "$amount" } $avgMean of numeric values
{ $avg: "$score" } $pushCollect every value into an array
{ $push: "$name" } $topNTop N ranked documents (5.2+)
{ $topN: { n: 3, sortBy: { score: -1 }, output: "$$ROOT" } } Tip: some names also exist as expression operators (for example $sum in $group vs expression form). Context decides which syntax MongoDB expects—check the individual tutorial when unsure.
Use this mental model before you write a $group stage.
goal = what you need per group (total / mean / list / top record)
buckets = empty map
for each document:
key = evaluate(_id expression)
put document into buckets[key]
update each accumulator state for that key
for each key in buckets:
emit {
_id: key,
field1: finalize(accumulator1),
field2: finalize(accumulator2),
...
} Major families below. The left sidebar lists every tutorial—this section only explains when each family is useful.
| Category | Used for | Examples |
|---|---|---|
| Numeric | Totals, means, extremes, spread | $sum, $avg, $min, $max |
| Arrays & objects | Collect values or merge documents | $push, $addToSet, $mergeObjects |
| First / last | Values based on input stream order | $first, $last, $firstN |
| Ranking | Best / worst documents with sortBy (5.2+) | $top, $topN, $bottom |
| N-variants | Arrays of N extremes or ordered values (5.2+) | $minN, $maxN, $lastN |
| Statistics | Standard deviation of numeric fields | $stdDevPop, $stdDevSamp |
| Custom | JavaScript when built-ins cannot express the rule | $accumulator |
For per-document math and conditionals, see the operators hub. For pipeline steps around $group, see aggregation stages.
A short starter set. Open any name for a full tutorial; use the sidebar for the complete catalog.
| Accumulator | Quick meaning |
|---|---|
$sum | Total values, or count with $sum: 1 |
$avg | Arithmetic mean of numbers |
$min / $max | Smallest / largest value in the group |
$push | Collect every value (duplicates kept) |
$addToSet | Collect unique values only |
$first / $last | First / last value seen (order-sensitive) |
$top / $topN | Best document(s) by sortBy (5.2+) |
$mergeObjects | Shallow-merge objects in the group |
Small orders collection. We keep completed orders, then compute count, revenue, average, and unique customers per store.
Four orders across two stores.
db.orders.insertMany([
{ _id: 1, storeId: "A", customerId: "c1", amount: 40, status: "completed" },
{ _id: 2, storeId: "A", customerId: "c2", amount: 60, status: "completed" },
{ _id: 3, storeId: "B", customerId: "c1", amount: 25, status: "completed" },
{ _id: 4, storeId: "A", customerId: "c2", amount: 15, status: "cancelled" }
]); orders.A has two completed orders and one cancelled.B has one completed order.$groupFilter to completed orders, then roll up several metrics per store in one stage.
db.orders.aggregate([
{ $match: { status: "completed" } },
{
$group: {
_id: "$storeId",
orderCount: { $sum: 1 },
revenue: { $sum: "$amount" },
avgOrder: { $avg: "$amount" },
customers: { $addToSet: "$customerId" }
}
},
{ $sort: { revenue: -1 } }
]); Match the business question to the family first; then pick a specific operator.
Common beginner traps when learning MongoDB accumulators.
Store numbers as numeric BSON types. Values like "120" are ignored by $sum and $avg—convert first if needed.
Missing or null inputs are often ignored by numeric accumulators. An empty numeric group can yield null for $avg.
$push can grow largeHuge groups with $push can hit the 100 MB per-group limit. Filter with $match earlier or reshape in stages.
{ total: { $sum: "$amount" } } inside $group is an accumulator. Per-document math belongs in $project / $addFields with expression operators.
$top, $bottom, $topN, $bottomN, and several N-variants require MongoDB 5.2 or later. Check your server version before relying on them.
| Idea | Practical tip |
|---|---|
| Accumulators are not “slow by default” | Cost comes from how many documents enter each group and what you collect |
| Filter early | Place $match before $group to shrink work |
| Indexes help the filter | Index fields used in early $match / sort stages when possible |
| Prefer built-ins | $sum / $avg beat custom $accumulator for standard rollups |
| Watch large arrays | Avoid unbounded $push on huge groups; project only needed fields |
Use explain() when a pipeline feels slow. Prefer selective filters and smaller working sets over micro-optimizing a single accumulator choice.
$group bucket.$group can run many accumulators together.One line: Accumulators answer “what is true for this whole group?”—totals, means, lists, and rankings inside $group.
Custom JavaScript rollups when built-in accumulators are not enough.
11 people found this page helpful