Docs Menu

Docs HomeLaunch & Manage MongoDBMongoDB Atlas

Paginate the Results Sequentially

On this page

  • Usage
  • Considerations
  • Retrieve Point of Reference
  • Syntax
  • Output
  • Search After a Specific Point of Reference
  • searchAfter Syntax
  • Output
  • Search Before a Specific Point of Reference
  • searchBefore Syntax
  • searchBefore Output
  • Examples
  • searchSequenceToken Query
  • Subsequent searchAfter and searchBefore Queries

On Atlas clusters running MongoDB 6.0.13+ or 7.0.5+, Atlas Search allows you to retrieve your $search query results sequentially after or before a reference point. You can use the $search searchAfter or searchBefore options to traverse results in-order and build "Next Page" and "Previous Page" functions in your application.

To jump to a page non-sequentially, you can use the $skip and $limit stages in your aggregation pipeline as demonstrated in the How to Divide Query Results into Discrete Pages tutorial. However, jumping to a page non-sequentially might be slow if your query results are large.

To retrieve paginated results sequentially, you must do the following:

  1. Create an Atlas Search index on the fields you want to query. To learn more, see Create an Atlas Search Index.

  2. Run a $search query that returns a point of reference. To learn more, see Retrieve Point of Reference.

  3. Use the point of reference in your subsequent $search query to retrieve the next or previous set of documents in the results.

Note

You can't use searchSequenceToken when you use $search inside a $lookup sub-pipeline. You can't use the searchAfter and searchBefore options in the same query because they are mutually exclusive.

If you update your collection between your initial and subsequent queries, Atlas Search reflects the updates in your subsequent query results. For example, suppose you sort the results by an updated_time field. If you update the documents between your first query and subsequent query, the same document might appear in both your query results. To avoid this, sort the results by an immutable field.

By default, Atlas Search sorts the documents in the results by the relevance score of the documents. If multiple documents in the results have identical scores, Atlas Search returns arbitrarily ordered results. To return documents in a determined order, use a unique field to sort your query results.

To learn how to sort your query results by an immutable or unique field, see Sort Atlas Search Results.

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.

searchSequenceToken
1[{
2 "$search": {
3 "index": "<index-name>",
4 "<operator-name>"|"<collector-name>": {
5 <operator-specification>|<collector-specification>
6 }
7 ...
8 },
9 {
10 "$project": {
11 { "paginationToken" : { "$meta" : "searchSequenceToken" } }
12 },
13 ...
14}]

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.

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.

searchSequenceToken
1{
2 "$search": {
3 "index": "<index-name>",
4 "<operator-name>"|"<collector-name>": {
5 <operator-specification>|<collector-specification>
6 }
7 "searchAfter": "<base64-encoded-token>"
8 ...
9 },
10 "$project": {
11 { "paginationToken" : { "$meta" : "searchSequenceToken" } }
12 },
13 ...
14}

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.

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.

searchSequenceToken
1{
2 "$search": {
3 "index": "<index-name>",
4 "<operator-name>"|"<collector-name>": {
5 <operator-specification>|<collector-specification>
6 }
7 "searchBefore": "<base64-encoded-token>"
8 ...
9 },
10 "$project": {
11 { "paginationToken" : { "$meta" : "searchSequenceToken" } }
12 },
13 ...
14}

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.

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.

The following query uses the following pipeline stages:

  • $search to do the following:

    • Search for the term war in title 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 to 10 documents.

  • $project stage to do the following:

    • Include only the title and released 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.

1db.movies.aggregate([
2 {
3 "$search": {
4 "text": {
5 "path": "title",
6 "query": "war"
7 },
8 "sort": {unused: {$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.

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 in title 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 to 10 documents.

  • $project stage to do the following:

    • Include only the title and released 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.

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.

1db.movies.aggregate([
2 {
3 "$search": {
4 "text": {
5 "path": "title",
6 "query": "war"
7 },
8 "sort": {unused: {$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]

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.

1db.movies.aggregate([
2 {
3 "$search": {
4 "text": {
5 "path": "title",
6 "query": "war"
7 },
8 "sort": {unused: {$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".

1db.movies.aggregate([
2 {
3 "$search": {
4 "text": {
5 "path": "title",
6 "query": "war"
7 },
8 "sort": {unused: {$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]
← Count Atlas Search Results