The MongoDB Aggregation Pipeline in 5 Minutes
The aggregation pipeline in MongoDB is a powerful tool for processing and aggregating data from collections. With it, you can perform transformations and computations across multiple documents to derive valuable insights.
While MongoDB also offers map-reduce and single-purpose aggregation methods, the aggregation pipeline has become the go-to method for data aggregation due to its efficiency and flexibility.
Key Takeaways
- The aggregation pipeline is essential for data processing and aggregation in MongoDB.
- It consists of multiple stages such as $match, $group, and $project to transform documents.
- Pipeline optimizations are automatic, enhancing performance.
- Each stage in the pipeline relies on the result from the previous stage.
- There are limitations on memory usage, but these can be managed with configuration options.
A Quick Example
Consider a collection "posts" with the following documents:
{
"title" : "my first post",
"author" : "Jim",
"likes" : 5
},
{
"title" : "my second post",
"author" : "Jim",
"likes" : 2
},
{
"title" : "hello world",
"author" : "Joe",
"likes" : 3
}
To calculate the total number of likes for each author, you would use:
db.posts.aggregate([
{$group: {_id: "$author", total_likes: { $sum: "$likes"}}}
])
This query generates the following results:
{
"_id" : "Joe",
"total_likes" : 3
},
{
"_id" : "Jim",
"total_likes" : 7
}
Pipeline Stages
The aggregation pipeline moves documents through various stages. Each stage performs specific transformations on the documents.
Our initial example used a single stage with $group. Now let’s illustrate multiple stages:
db.posts.aggregate([
{$match: { author: "Joe"}},
{$group: {_id: "$author", total_likes: { $sum: "$likes"}}}
])
This results in:
{
"_id" : "Joe",
"total_likes" : 3
}
Notice how each stage in the pipeline operates on the output of the previous stage. Here, $match filters the documents for author Joe, and $group aggregates the results.
Pipeline Optimization
Executing filtering and sorting early in the pipeline generally improves performance by reducing the number of documents to process. The $match and $sort stages can utilize indexes effectively when they appear at the start of the pipeline.
MongoDB's aggregation framework includes built-in optimization that can automatically reorder stages to maximize efficiency:
{ $sort: { likes: -1 }},
{ $match: { author: 'Joe' }}
This may be optimized to:
{ $match: { author: 'Joe' }},
{ $sort: { likes: -1 }}
Such optimizations occur automatically in modern MongoDB versions, and you can explore them using the explain function to see how queries are transformed under the hood.
MongoDB Aggregation Pipeline Examples
Let's consider this test "posts" collection:
{
"title" : "my first post",
"author" : "Jim",
"likes" : 5,
"tags" : ["angular", "react", "javascript"]
},
{
"title" : "my second post",
"author" : "Jim",
"likes" : 2,
"tags" : ["javascript", "react", "vue"]
},
{
"title" : "hello world",
"author" : "Joe",
"likes" : 3,
"tags" : ["vue", "react"]
}
$group
db.posts.aggregate([
{ $group: { _id:"$author", titles: { $push:"$title"}}}
])
Resulting in:
{
"_id" : "Joe",
"titles" : [ "hello world" ]
},
{
"_id" : "Jim",
"titles" : [ "my first post", "my second post" ]
}
The $group stage above aggregates titles by author.
$match
db.posts.aggregate([
{ $match: { author:"Jim" }}
])
Results in:
{
"_id" : ObjectId("5c58e5bf186d4fe7f31c652e"),
"title" : "my first post",
"author" : "Jim",
"likes" : 5,
"tags" : [ "angular", "react", "javascript" ]
},
{
"_id" : ObjectId("5c58e5bf186d4fe7f31c652f"),
"title" : "my second post",
"author" : "Jim",
"likes" : 2,
"tags" : [ "javascript", "react", "vue" ]
}
This $match stage filters documents where the author is "Jim".
$project
db.posts.aggregate([
{ $project: { author:1, abbrev:{ $substr: [ "$title", 0, 3 ] }} }
])
Leading to:
{
"_id" : ObjectId("5c58e5bf186d4fe7f31c652e"),
"author" : "Jim",
"abbrev" : "my "
},
{
"_id" : ObjectId("5c58e5bf186d4fe7f31c652f"),
"author" : "Jim",
"abbrev" : "my "
},
{
"_id" : ObjectId("5c58e5bf186d4fe7f31c6530"),
"author" : "Joe",
"abbrev" : "hel"
}
Here, $project allows selection of fields and creates a new field for abbreviation.
$sum
db.posts.aggregate([
{ $group: { _id: "$author", total_likes: { $sum: "$likes" }} }
])
Yielding:
{
"_id" : "Joe",
"total_likes" : 3
},
{
"_id" : "Jim",
"total_likes" : 7
}
The $sum accumulator aggregates total likes across documents by author.
$unwind
db.posts.aggregate([
{ $unwind: "$tags" }
])
Transforms to:
{
"_id" : ObjectId("5c58e5bf186d4fe7f31c652e"),
"title" : "my first post",
"author" : "Jim",
"likes" : 5,
"tags" : "angular"
},
{
"_id" : ObjectId("5c58e5bf186d4fe7f31c652e"),
"title" : "my first post",
"author" : "Jim",
"likes" : 5,
"tags" : "react"
},
{
"_id" : ObjectId("5c58e5bf186d4fe7f31c652e"),
"title" : "my first post",
"author" : "Jim",
"likes" : 5,
"tags" : "javascript"
}
With $unwind, each element of the "tags" array yields a separate document.
Performance & Limitations
The aggregation pipeline outputs results in a cursor or writes to a collection. Results follow the standard 16MB document size limit, and each stage is capped at 100MB RAM. You can use the allowDiskUse option if more memory is needed to prevent errors.
FAQ
What is the MongoDB aggregation pipeline?
The MongoDB aggregation pipeline is a framework for transforming and processing documents in a collection to aggregate results using various stages.
How does the aggregation pipeline improve performance?
By using early-stage filtering and sorting, leveraging index use, and utilizing MongoDB's automatic query optimizations.
What are some common stages in the aggregation pipeline?
Common stages include $match for filtering, $group for aggregating data, $project for adjusting document shapes, and $unwind for flattening arrays.
What limitations should I be aware of?
Beware of the 16MB document and 100MB RAM limits per stage; use allowDiskUse for more extensive operations.

