Paginate the Results
On this page
On Atlas clusters running MongoDB 6.0.13+ or 7.0.5+, use Atlas Search
to retrieve your $search
query results sequentially after or
before a reference point. Use the $search
searchAfter
or
searchBefore
options to traverse results in-order and build
"Next Page" and "Previous Page" functions in your application.
Usage
To retrieve paginated results, perform the following steps:
Create an index on the fields you want to query.
Run a
$search
query that returns a point of reference. To learn more, see Retrieve Point of Reference.Use the point of reference in your subsequent
$search
query to retrieve the next or previous set of documents in the results.To learn more about retrieving results to build a "Next Page" function, see Search After a Specific Point of Reference.
To learn more about retrieving results to build a "Previous Page" function, see Search Before a Specific Point of Reference.
To jump to a page in your results, combine
$skip
and$limit
with$search
searchAfter
orsearchBefore
options. For example, to jump to results from Page 3 to Page 5, with 10 results per page, do the following:Retrieve results using
searchAfter
with the point of reference for the last result on Page 3 (Result 30).Use
$skip
to skip the 10 results on Page 4 (Results 31-40) and$limit
to limit the results to 10 documents.Return results for Page 5 (Results 41-50).
Here, using
$skip
with thesearchAfter
option optimizes the query to skip only 1 page of results (10 documents). By comparison, if you use$skip
without the$search
searchAfter
option, the query skips 4 pages of results (40 documents). To learn more, see Jump from Page 2 to Page 5 UsingsearchAfter
and$skip
.
Considerations
A tie occurs when you sort on a field for which multiple documents
have identical values. MongoDB doesn't guarantee ordering of tied
query results, which can lead to duplication and inconsistency when
you use searchAfter
and searchBefore
. Apply the following
principles to ensure deterministic search behavior:
Sort your query by a unique field to prevent relevance score ties.
If you want to primarily sort by a non-unique field, add a secondary sort clause on a unique field to serve as a tiebreaker.
Sort your query results by an immutable field. Atlas Search reflects the updates you make to your collection between initial and subsequent queries. If you sort by a mutable field such as
updated_time
and you update your collection between your first and second queries, Atlas Search may order the same documents differently.
To learn how to sort your query results by an immutable or unique field, see Sort Atlas Search Results.
Retrieve Point of Reference
To retrieve query results at a certain point, you must provide the point
of reference in your $search
query. You can retrieve the
reference point by using the $meta
keyword
searchSequenceToken
in the $project
stage after your
$search
stage.
Syntax
1 [{ 2 "$search": { 3 "index": "<index-name>", 4 "<operator-name>"|"<collector-name>": { 5 <operator-specification>|<collector-specification> 6 } 7 "sort": { 8 "score": { 9 "$meta": "searchScore", _id:1 10 } 11 } 12 ... 13 }, 14 { 15 "$project": { 16 { "paginationToken" : { "$meta" : "searchSequenceToken" } } 17 }, 18 ... 19 }]
Output
The searchSequenceToken
generates a Base64-encoded token for each
document in the results. The length of the token increases with the number
of fields specified in the sort option of your query.
The token isn't tied to a snapshot of the database.
The documents in the results are sorted in the default order, unless you
specify the sort
option in your query. To learn about sorting your
results, see Sort Atlas Search Results.
Search After a Specific Point of Reference
To search after a reference point, you must specify the reference point
in your $search
query by using the searchAfter
option with
the token generated by searchSequenceToken
. You can use the token
generated by searchSequenceToken
only when you rerun the
$search
query for which searchSequenceToken
generated
the token. The semantics (search fields and values) of the subsequent
$search
query in which you use the token must be identical
to the query for which searchSequenceToken
generated the token.
You can use the searchAfter
option to build a "Next Page" function
in your application. For a demonstration of this, see the example on this page.
searchAfter
Syntax
1 { 2 "$search": { 3 "index": "<index-name>", 4 "<operator-name>"|"<collector-name>": { 5 <operator-specification>|<collector-specification> 6 }, 7 "searchAfter": "<base64-encoded-token>", 8 "sort": { 9 "score": { 10 "$meta": "searchScore", _id:1 11 } 12 } 13 ... 14 }, 15 "$project": { 16 { "paginationToken" : { "$meta" : "searchSequenceToken" } } 17 }, 18 ... 19 }
Output
Atlas Search returns the documents in the results after the specified token.
Atlas Search returns the generated tokens for the documents in the results
because you specified the searchSequenceToken
in the
$project
stage after the $search
stage (as
shown in line 11). These tokens can be used as a reference point for
another query with the same semantics.
The documents in the results are sorted in the default order, unless you
specify the sort
option in your query. To learn about sorting your
results, see Sort Atlas Search Results.
Search Before a Specific Point of Reference
To search before a reference point, you must specify the reference point
in your $search
query by using the searchBefore
option
with the token generated by searchSequenceToken
. You can use the token
generated by searchSequenceToken
only when you rerun the
$search
query for which searchSequenceToken
generated
the token. The semantics (search fields and values) of the subsequent
$search
query in which you use the token must be identical
to the query for which searchSequenceToken
generated the token.
You can build a "Previous Page" function in your application using the
searchBefore
option. To build a "Previous Page" function, combine
the following:
For a demonstration of this, see the searchBefore
query examples on this page.
searchBefore
Syntax
1 { 2 "$search": { 3 "index": "<index-name>", 4 "<operator-name>"|"<collector-name>": { 5 <operator-specification>|<collector-specification> 6 }, 7 "searchBefore": "<base64-encoded-token>", 8 "sort": { 9 "score": { 10 "$meta": "searchScore", _id:1 11 } 12 } 13 ... 14 }, 15 "$project": { 16 { "paginationToken" : { "$meta" : "searchSequenceToken" } } 17 }, 18 ... 19 }
searchBefore
Output
Atlas Search returns documents in the results preceding the specified token in
reverse order. Atlas Search also returns the generated tokens for the documents
in the results because you specified the searchSequenceToken
in the
$project
stage after the $search
stage (as
shown in line 11). These tokens can be used as a reference point for
another query with the same semantics.
Examples
The following examples use the sample-mflix.movies
collection, which has an Atlas Search index named default
with dynamic
mappings. If you load the collection and create the index, you can run
the following queries against the collection.
searchSequenceToken
Query
The following query uses the following pipeline stages:
$search
to do the following:Search for the term
war
intitle
field of the collection.Sort the results first by score and then by the value of the
released
field in ascending order for documents with identical scores.
$limit
stage to limit the results to10
documents.$project
stage to do the following:Include only the
title
andreleased
fields.Add the following fields:
Field named
paginationToken
that contains the Base64-encoded token for each document.Field named
score
that contains the relevance score of each document.
1 db.movies.aggregate([ 2 { 3 "$search": { 4 "text": { 5 "path": "title", 6 "query": "war" 7 }, 8 "sort": {score: {$meta: "searchScore"}, "released": 1} 9 } 10 }, 11 { 12 "$limit": 10 13 }, 14 { 15 "$project": { 16 "_id": 0, 17 "title": 1, 18 "released": 1, 19 "paginationToken" : { "$meta" : "searchSequenceToken" }, 20 "score": {$meta: "searchScore"} 21 } 22 } 23 ])
1 [ 2 { 3 title: 'War', 4 released: ISODate('2002-03-14T00:00:00.000Z'), 5 paginationToken: 'CMFRGgYQup3BhQgaCSkAQCKS7AAAAA==', 6 score: 3.3774025440216064 7 }, 8 { 9 title: 'War', 10 released: ISODate('2014-09-21T00:00:00.000Z'), 11 paginationToken: 'CMelARoGELqdwYUIGgkpAAiClUgBAAA=', 12 score: 3.3774025440216064 13 }, 14 { 15 title: 'War Photographer', 16 paginationToken: 'CMBRGgYQuq+ngwgaAmAA', 17 score: 2.8268959522247314 18 }, 19 { 20 title: "Troma's War", 21 released: ISODate('1989-11-18T00:00:00.000Z'), 22 paginationToken: 'CL8kGgYQuq+ngwgaCSkAbP8QkgAAAA==', 23 score: 2.8268959522247314 24 }, 25 { 26 title: 'The War', 27 released: ISODate('1994-11-04T00:00:00.000Z'), 28 paginationToken: 'CI0wGgYQuq+ngwgaCSkAnIKEtgAAAA==', 29 score: 2.8268959522247314 30 }, 31 { 32 title: 'War Stories', 33 released: ISODate('1996-05-09T00:00:00.000Z'), 34 paginationToken: 'CPIyGgYQuq+ngwgaCSkA/DifwQAAAA==', 35 score: 2.8268959522247314 36 }, 37 { 38 title: "Gaston's War", 39 released: ISODate('1997-10-23T00:00:00.000Z'), 40 paginationToken: 'CMQ7GgYQuq+ngwgaCSkALPBSzAAAAA==', 41 score: 2.8268959522247314 42 }, 43 { 44 title: 'Shooting War', 45 released: ISODate('2000-12-07T00:00:00.000Z'), 46 paginationToken: 'CMJJGgYQuq+ngwgaCSkAOOhG4wAAAA==', 47 score: 2.8268959522247314 48 }, 49 { 50 title: "Varian's War", 51 released: ISODate('2001-04-22T00:00:00.000Z'), 52 paginationToken: 'CM5IGgYQuq+ngwgaCSkAGEkD5gAAAA==', 53 score: 2.8268959522247314 54 }, 55 { 56 title: "Hart's War", 57 released: ISODate('2002-02-15T00:00:00.000Z'), 58 paginationToken: 'CMtJGgYQuq+ngwgaCSkAjBYH7AAAAA==', 59 score: 2.8268959522247314 60 } 61 ]
Note
The tokens for the documents in your results might be different.
Replace the tokens in the subsequent queries with the tokens that Atlas Search returned in your
results before running the searchAfter
or searchBefore
queries.
Subsequent searchAfter
and searchBefore
Queries
The following queries use the token from another query with the same
semantics to retrieve paginated results after or before the specified
token. If you ran the example searchSequenceToken
Query, the
tokens for the documents in your results might be different. Make sure
to replace the tokens in the queries in this section with the tokens
returned in your query result.
The queries use the following pipeline stages:
$search
stage to do the following:Search for documents from the Atlas Search results for the term
war
intitle
field.Sort the results first by score and then by the value of the
released
field in ascending order for documents with identical scores.
$limit
stage to limit the results to10
documents.$project
stage to do the following:Include only the
title
andreleased
fields in the documents.Add the following fields:
Field named
paginationToken
that contains the Base64-encoded token for each document.Field named
score
that contains the relevance score of each document.
Search After the Reference Point
The following query requests documents in the Atlas Search results that contain
the term war
in title
field after the specified reference
point. It uses the token (on line 58) associated with the last document
from the searchSequenceToken
Query results as the reference point
to retrieve the next 10
documents in the results.
1 db.movies.aggregate([ 2 { 3 "$search": { 4 "text": { 5 "path": "title", 6 "query": "war" 7 }, 8 "sort": {score: {$meta: "searchScore"}, "released": 1}, 9 "searchAfter": "CMtJGgYQuq+ngwgaCSkAjBYH7AAAAA==" 10 } 11 }, 12 { 13 "$limit": 10 14 }, 15 { 16 "$project": { 17 "_id": 0, 18 "title": 1, 19 "released": 1, 20 "paginationToken" : { "$meta" : "searchSequenceToken" }, 21 "score": { "$meta": "searchScore" } 22 } 23 } 24 ])
1 [ 2 { 3 title: 'The War', 4 released: ISODate('2007-09-23T00:00:00.000Z'), 5 paginationToken: 'CP9xGgYQuq+ngwgaCSkA1KkvFQEAAA==', 6 score: 2.8268959522247314 7 }, 8 { 9 title: 'War, Inc.', 10 released: ISODate('2008-06-13T00:00:00.000Z'), 11 paginationToken: 'COhuGgYQuq+ngwgaCSkAtDh/GgEAAA==', 12 score: 2.8268959522247314 13 }, 14 { 15 title: 'War, Inc.', 16 released: ISODate('2008-06-13T00:00:00.000Z'), 17 paginationToken: 'COluGgYQuq+ngwgaCSkAtDh/GgEAAA==', 18 score: 2.8268959522247314 19 }, 20 { 21 title: 'War Dance', 22 released: ISODate('2008-11-01T00:00:00.000Z'), 23 paginationToken: 'CONvGgYQuq+ngwgaCSkAYFlVHQEAAA==', 24 score: 2.8268959522247314 25 }, 26 { 27 title: 'War Horse', 28 released: ISODate('2011-12-25T00:00:00.000Z'), 29 paginationToken: 'CJWFARoGELqvp4MIGgkpAEyEcjQBAAA=', 30 score: 2.8268959522247314 31 }, 32 { 33 title: 'Cold War', 34 released: ISODate('2012-11-08T00:00:00.000Z'), 35 paginationToken: 'CJGUARoGELqvp4MIGgkpAPBQ3ToBAAA=', 36 score: 2.8268959522247314 37 }, 38 { 39 title: 'Drug War', 40 released: ISODate('2013-04-04T00:00:00.000Z'), 41 paginationToken: 'CMWTARoGELqvp4MIGgkpAMRX0j0BAAA=', 42 score: 2.8268959522247314 43 }, 44 { 45 title: 'War Story', 46 released: ISODate('2014-07-30T00:00:00.000Z'), 47 paginationToken: 'CJCdARoGELqvp4MIGgkpAPyQhEcBAAA=', 48 score: 2.8268959522247314 49 }, 50 { 51 title: 'A War', 52 released: ISODate('2015-09-10T00:00:00.000Z'), 53 paginationToken: 'CL2kARoGELqvp4MIGgkpAECNtE8BAAA=', 54 score: 2.8268959522247314 55 }, 56 { 57 title: 'War Pigs', 58 released: ISODate('2015-09-18T00:00:00.000Z'), 59 paginationToken: 'CJ6kARoGELqvp4MIGgkpACDA3U8BAAA=', 60 score: 2.8268959522247314 61 } 62 ]
Search Before the Reference Point
The following query requests Atlas Search results for the term war
in
title
field before the specified reference point. It uses the
token (on line 59) associated with the last document in the sample searchAfter
query results as the
reference point to retrieve the preceding 10
documents from the
results.
1 db.movies.aggregate([ 2 { 3 "$search": { 4 "text": { 5 "path": "title", 6 "query": "war" 7 }, 8 "sort": {score: {$meta: "searchScore"}, "released": 1}, 9 "searchBefore": "CJ6kARoGELqvp4MIGgkpACDA3U8BAAA=" 10 } 11 }, 12 { 13 "$limit": 10 14 }, 15 { 16 "$project": { 17 "_id": 0, 18 "title": 1, 19 "released": 1, 20 "paginationToken" : { "$meta" : "searchSequenceToken" }, 21 "score": { "$meta": "searchScore" } 22 } 23 } 24 ])
1 [ 2 { 3 title: 'A War', 4 released: ISODate('2015-09-10T00:00:00.000Z'), 5 paginationToken: 'CL2kARoGELqvp4MIGgkpAECNtE8BAAA=', 6 score: 2.8268959522247314 7 }, 8 { 9 title: 'War Story', 10 released: ISODate('2014-07-30T00:00:00.000Z'), 11 paginationToken: 'CJCdARoGELqvp4MIGgkpAPyQhEcBAAA=', 12 score: 2.8268959522247314 13 }, 14 { 15 title: 'Drug War', 16 released: ISODate('2013-04-04T00:00:00.000Z'), 17 paginationToken: 'CMWTARoGELqvp4MIGgkpAMRX0j0BAAA=', 18 score: 2.8268959522247314 19 }, 20 { 21 title: 'Cold War', 22 released: ISODate('2012-11-08T00:00:00.000Z'), 23 paginationToken: 'CJGUARoGELqvp4MIGgkpAPBQ3ToBAAA=', 24 score: 2.8268959522247314 25 }, 26 { 27 title: 'War Horse', 28 released: ISODate('2011-12-25T00:00:00.000Z'), 29 paginationToken: 'CJWFARoGELqvp4MIGgkpAEyEcjQBAAA=', 30 score: 2.8268959522247314 31 }, 32 { 33 title: 'War Dance', 34 released: ISODate('2008-11-01T00:00:00.000Z'), 35 paginationToken: 'CONvGgYQuq+ngwgaCSkAYFlVHQEAAA==', 36 score: 2.8268959522247314 37 }, 38 { 39 title: 'War, Inc.', 40 released: ISODate('2008-06-13T00:00:00.000Z'), 41 paginationToken: 'COluGgYQuq+ngwgaCSkAtDh/GgEAAA==', 42 score: 2.8268959522247314 43 }, 44 { 45 title: 'War, Inc.', 46 released: ISODate('2008-06-13T00:00:00.000Z'), 47 paginationToken: 'COhuGgYQuq+ngwgaCSkAtDh/GgEAAA==', 48 score: 2.8268959522247314 49 }, 50 { 51 title: 'The War', 52 released: ISODate('2007-09-23T00:00:00.000Z'), 53 paginationToken: 'CP9xGgYQuq+ngwgaCSkA1KkvFQEAAA==', 54 score: 2.8268959522247314 55 }, 56 { 57 title: "Hart's War", 58 released: ISODate('2002-02-15T00:00:00.000Z'), 59 paginationToken: 'CMtJGgYQuq+ngwgaCSkAjBYH7AAAAA==', 60 score: 2.8268959522247314 61 } 62 ]
For the preceding query, note that Atlas Search results are in reverse order.
The following query uses the $limit
stage with the
toArray() and
reverse()
methods to build a function similar to "Previous Page".
1 db.movies.aggregate([ 2 { 3 "$search": { 4 "text": { 5 "path": "title", 6 "query": "war" 7 }, 8 "sort": {score: {$meta: "searchScore"}, "released": 1}, 9 "searchBefore": "CJ6kARoGELqvp4MIGgkpACDA3U8BAAA=" 10 } 11 }, 12 { 13 "$limit": 10 14 }, 15 { 16 "$project": { 17 "_id": 0, 18 "title": 1, 19 "released": 1, 20 "paginationToken" : { "$meta" : "searchSequenceToken" }, 21 "score": { "$meta": "searchScore" } 22 } 23 } 24 ]).toArray().reverse()
1 [ 2 { 3 title: "Hart's War", 4 released: ISODate('2002-02-15T00:00:00.000Z'), 5 paginationToken: 'CMtJGgYQuq+ngwgaCSkAjBYH7AAAAA==', 6 score: 2.8268959522247314 7 }, 8 { 9 title: 'The War', 10 released: ISODate('2007-09-23T00:00:00.000Z'), 11 paginationToken: 'CP9xGgYQuq+ngwgaCSkA1KkvFQEAAA==', 12 score: 2.8268959522247314 13 }, 14 { 15 title: 'War, Inc.', 16 released: ISODate('2008-06-13T00:00:00.000Z'), 17 paginationToken: 'COhuGgYQuq+ngwgaCSkAtDh/GgEAAA==', 18 score: 2.8268959522247314 19 }, 20 { 21 title: 'War, Inc.', 22 released: ISODate('2008-06-13T00:00:00.000Z'), 23 paginationToken: 'COluGgYQuq+ngwgaCSkAtDh/GgEAAA==', 24 score: 2.8268959522247314 25 }, 26 { 27 title: 'War Dance', 28 released: ISODate('2008-11-01T00:00:00.000Z'), 29 paginationToken: 'CONvGgYQuq+ngwgaCSkAYFlVHQEAAA==', 30 score: 2.8268959522247314 31 }, 32 { 33 title: 'War Horse', 34 released: ISODate('2011-12-25T00:00:00.000Z'), 35 paginationToken: 'CJWFARoGELqvp4MIGgkpAEyEcjQBAAA=', 36 score: 2.8268959522247314 37 }, 38 { 39 title: 'Cold War', 40 released: ISODate('2012-11-08T00:00:00.000Z'), 41 paginationToken: 'CJGUARoGELqvp4MIGgkpAPBQ3ToBAAA=', 42 score: 2.8268959522247314 43 }, 44 { 45 title: 'Drug War', 46 released: ISODate('2013-04-04T00:00:00.000Z'), 47 paginationToken: 'CMWTARoGELqvp4MIGgkpAMRX0j0BAAA=', 48 score: 2.8268959522247314 49 }, 50 { 51 title: 'War Story', 52 released: ISODate('2014-07-30T00:00:00.000Z'), 53 paginationToken: 'CJCdARoGELqvp4MIGgkpAPyQhEcBAAA=', 54 score: 2.8268959522247314 55 }, 56 { 57 title: 'A War', 58 released: ISODate('2015-09-10T00:00:00.000Z'), 59 paginationToken: 'CL2kARoGELqvp4MIGgkpAECNtE8BAAA=', 60 score: 2.8268959522247314 61 } 62 ]