Jamie Street
Jamie Street

Reputation: 1547

Get MongoDB (aggregate) matched document total before pagination plus results?

I'm aware there are a few questions very similar to this, but I haven't been able to find one which clearly outlines how to keep both the total count after match (in this case geoNear), but before skip/limit operations, as well as the skip/limit results.

My current aggregation pipeline is:

[ { '$geoNear': 
     { near: [Object],
       maxDistance: 4000,
       distanceField: 'distance',
       spherical: true,
       query: {} } },
  { '$sort': { distance: 1 } },
  { '$skip': 0 },
  { '$limit': 20 } ]

Ideally I'd want something like this returned:

{
  total: 123,
  results: [<results respecting $skip & $limit>]
}

Upvotes: 2

Views: 473

Answers (1)

Bertrand Martel
Bertrand Martel

Reputation: 45402

You can do :

  • 1 $group to sum result of previous $geonear match and push the $$ROOT document to keep the record
  • 1 $unwind necessary to remove the array
  • your $skip
  • your $limit
  • 1 last $group to format the final result with only the sum amount and the JSON array

Query is :

db.coll.aggregate([{
    $geoNear: {
        near: [Object],
        maxDistance: 4000,
        distanceField: 'distance',
        spherical: true,
        query: {}
    }
}, {
    $sort: {
        distance: 1
    }
}, {
    $group: {
        _id: 0,
        count: {
            $sum: 1
        },
        document: {
            $push: "$$ROOT"
        }
    }
}, {
    $unwind: "$document"
}, {
    $skip: 0
}, {
    $limit: 20
}, {
    $group: {
        _id: 0,
        total: {
            $first: "$count"
        },
        results: {
            $push: "$document"
        }
    }
}])

You can use $slice instead of $skip and $limit and preserveNullAndEmptyArrays for the $unwind part to assure an empty result array :

db.coll.aggregate([{
    $geoNear: {
        near: [Object],
        maxDistance: 4000,
        distanceField: 'distance',
        spherical: true,
        query: {}
    }
}, {
    $sort: {
        distance: 1
    }
}, {
    $group: {
        _id: 0,
        count: {
            $sum: 1
        },
        document: {
            $push: "$$ROOT"
        }
    }
}, {
    $project: {
        count: 1,
        document: { $slice: ["$document", 0, 20] }
    }
}, {
    $unwind: { path: "$document", preserveNullAndEmptyArrays: true }
}, {
    $group: {
        _id: 0,
        total: {
            $first: "$count"
        },
        results: {
            $push: "$document"
        }
    }
}])

Upvotes: 4

Related Questions