MongoDB Query to Find Average Per Group Using Aggregation
Use the MongoDB aggregation pipeline with
$group and $avg operators like this: db.collection.aggregate([{ $group: { _id: "$groupField", averageValue: { $avg: "$valueField" } } }]) to find the average per group.Examples
Input[{ category: "fruit", price: 10 }, { category: "fruit", price: 20 }, { category: "vegetable", price: 30 }]
Output[{ _id: "fruit", averageValue: 15 }, { _id: "vegetable", averageValue: 30 }]
Input[{ type: "A", score: 50 }, { type: "A", score: 70 }, { type: "B", score: 90 }, { type: "B", score: 110 }]
Output[{ _id: "A", averageValue: 60 }, { _id: "B", averageValue: 100 }]
Input[]
Output[]
How to Think About It
To find the average per group, first decide which field you want to group by. Then, for each group, calculate the average of the target numeric field. MongoDB's aggregation framework lets you group documents by a field and apply the $avg operator to compute the average value within each group.
Algorithm
1
Identify the field to group documents by.2
Use the aggregation pipeline with a $group stage.3
In the $group stage, set _id to the group field.4
Use $avg to calculate the average of the target numeric field for each group.5
Return the grouped results with their average values.Code
mongodb
db.sales.aggregate([
{
$group: {
_id: "$category",
averagePrice: { $avg: "$price" }
}
}
])Output
[
{ "_id": "fruit", "averagePrice": 15 },
{ "_id": "vegetable", "averagePrice": 30 }
]
Dry Run
Let's trace the aggregation on a sample collection with documents having categories and prices.
1
Group documents by category
Group all documents with category 'fruit' together and those with 'vegetable' together.
2
Calculate average price per group
For 'fruit', average (10 + 20) / 2 = 15; for 'vegetable', average is 30.
| Category | Prices | Average Price |
|---|---|---|
| fruit | [10, 20] | 15 |
| vegetable | [30] | 30 |
Why This Works
Step 1: Grouping with $group
The $group stage collects documents sharing the same value in the specified field, here category.
Step 2: Calculating average with $avg
Within each group, $avg computes the mean of the price field values.
Alternative Approaches
Using Map-Reduce
mongodb
db.sales.mapReduce( function() { emit(this.category, this.price); }, function(key, values) { return Array.avg(values); }, { out: "average_prices" } )
Map-Reduce is more complex and slower than aggregation but can be used for custom calculations.
Using $group with $sum and $count
mongodb
db.sales.aggregate([
{
$group: {
_id: "$category",
total: { $sum: "$price" },
count: { $sum: 1 }
}
},
{
$project: {
averagePrice: { $divide: ["$total", "$count"] }
}
}
])Manually calculates average by dividing sum by count, useful if you want more control.
Complexity: O(n) time, O(k) space
Time Complexity
The aggregation scans all n documents once to group them, so time is O(n).
Space Complexity
Space depends on the number of groups k, as it stores intermediate results per group.
Which Approach is Fastest?
The aggregation pipeline with $group and $avg is faster and more readable than map-reduce.
| Approach | Time | Space | Best For |
|---|---|---|---|
| Aggregation $group + $avg | O(n) | O(k) | Simple average per group, best performance |
| Map-Reduce | O(n) | O(k) | Complex custom calculations, slower |
| Aggregation $group + $sum/$count | O(n) | O(k) | Manual average calculation, more control |
Always use the aggregation framework's $group and $avg operators for efficient average calculations per group.
Beginners often forget to set the _id field in $group, which is required to specify the grouping key.