MongoDB Pagination: Retrieving Paginated Records and Total Count Simultaneously

This article demonstrates how to implement pagination in MongoDB while fetching both the paginated records and the total count in a single query. The solution leverages MongoDB's aggregation pipeline with the $facet stage, which is documented in the official MongoDB documentation.

According to MongoDB's official documentation:

Input documents are passed to the $facet stage only once. $facet enables various aggregations on the same set of input documents, without needing to retrieve the input documents multiple times.

This approach processes the same dataset through multiple aggregation paths simultaneously. Since there is no secondary query involved, it offers better performance compared to traditional pagination methods found in relational databases. However, since aggregate operations return documents, result parsing requires manual handling and type conversion.

Implementation Using $facet

The following aggregation pipeline demonstrates how to achieve this:

{
    '$facet': {
        'totalCount': [
            {
                '$count': 'total'
            }
        ],
        'records': [
            {
                '$sort': {
                    'createdAt': -1
                }
            },
            {
                '$skip': 10
            },
            {
                '$limit': 20
            }
        ]
    }
}

Understanding the Result Structure

The query returns a single document containing both the count and the paginated records. The output follows this structure:

{
    "totalCount": [
        {
            "total": 14453
        }
    ],
    "records": [
        {
            "timestamp": "2021-01-21 08:00:28",
            "valueX": "0.0000",
            "valueY": "0.2089"
        },
        {
            "timestamp": "2021-01-21 08:01:19",
            "valueX": "0.0000",
            "valueY": "0.3256"
        }
    ]
}

It is important to note that MongoDB has a document size limit of 16MB. Since pagination is being used, the records array should remain reasonably sized, making this concern negligible in most use cases.

Handling Results in Java

When working with the Java driver, the result requires manual extraction:

Document result = (Document) aggregationResult.get(0);

List<Document> countList = (List<Document>) result.get("totalCount");
Integer totalRecords = countList.get(0).getInteger("total");

List<Document> pageData = (List<Document>) result.get("records");

While this parsing approach is not elegant, it is necessary for extracting both values from the compound resposne.

Alternative: Using Cursor Count in Mongo Shell

For MongoDB shell operations, the cursor.count(applySkipLimit) method provides additional flexibility. When applySkipLimit is set to true, the count applies the skip and limit constraints. When set to false, it returns the total count ignoring pagination parameters. Consult the official MongoDB documentation for detailed behavior.

Tags: mongodb Pagination aggregation-framework facet NoSQL

Posted on Sat, 16 May 2026 08:45:34 +0000 by kinaski