1. Overview
In this article, let’s calculate count using facet in MongoDB, introduced in version 3.4. It processes multiple aggregation pipelines within a single stage on the same set of input documents. Each sub-pipeline has its own field in the output document where we store the results as an array of documents.
2. MongoDB Facet
We must pass the input documents to the facet stage only once. The facet enables various aggregations on the same set of input documents, with no need to retrieve the input documents multiple times.
The $facet stage has the following form:
{ $facet: { <outputField1>: [ <stage1>, <stage2>, ... ], <outputField2>: [ <stage1>, <stage2>, ... ], ... } }
2.1. $count
When you use $count
, it calculates the number of documents input to the state and passes the count as a document to the next stage.
Assume we have three records in the collection as below:
[ { "_id": ObjectId("5fc4d0009a25e8cfbe306381"), "groupName": "A", "team1": { "tName": "Chicago Bears" }, "team2": { "tName": "Green Bay Packers" } }, { "_id": ObjectId("5fc4d0019a25e8cfbe3063ff"), "groupName": "A", "team1": { "tName": "Nashville SC" }, "team2": { "tName": "Columbus Crew" } }, { "_id": ObjectId("5fc4d0019a25e8cfbe3063f4"), "groupName": "A", "team1": { "tName": "yyyy" }, "team2": { "tName": "xxxx" } } ]
Let’s use the $count
aggregation to calculate the number of records.
db.collection.aggregate([ { "$match": { "groupName": "A" } }, { "$count": "totalRecords" } ])
If you execute the above query, you can expect the below result:
[ { "totalRecords": 3 } ]
Let’s assume that you want to group team1
and team2
along with count
as the required result.
2.2. MongoDB facet count
You can pass the input documents to the $facet aggregation pipeline. In the below example, the $facet has multiple sub-pipelines i.e., group
and count
. Each sub-pipeline of the aggregation pipeline $facet receives the same set of input documents.
These sub-pipelines are completely independent of one another and store the output of the document array output in separate fields in the output document. We can not use the output of one sub-pipeline as the input for a different sub-pipeline within the same $facet
stage.
db.collection.aggregate([ { "$match": { "groupName": "A" } }, { "$facet": { "team": [ { "$group": { "_id": "team", "team1": { "$push": "$team1.tName" }, "team2": { "$push": "$team2.tName" } } } ], "total": [ { "$count": "totalRecords" } ] } } ])
The above query produces the below result:
[ { "team": [ { "_id": "team", "team1": [ "Chicago Bears", "Nashville SC", "yyyy" ], "team2": [ "Green Bay Packers", "Columbus Crew", "xxxx" ] } ], "total": [ { "totalRecords": 3 } ] } ]
3. Conclusion
You can customize the $facet
aggregation pipeline however you want and based on your requirements. Since each sub-pipeline in the $facet
aggregation pipeline receives the same set of input documents, this certainly prevents you from making multiple DB calls to the database server.
If we haven’t had $facet
, we could have made two database calls: one to group the team names and another for the count
.
You can find code samples in our GitHub repository. If you are interested in more related topics of MongoDB, refer to these articles.