Skip to content

MongoDB Facet count

  • by
MongoDB Facet count

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.

Leave a Reply

Your email address will not be published. Required fields are marked *