MongoDB Atlas Search: $searchBefore returns the same results as $searchAfter
I’m implementing pagination in MongoDB Atlas Search using the $search stage with searchAfter and searchBefore tokens.
Here’s my aggregation query:
[
{
$search: {
index: "search-index",
text: { query: "20", path: "name" },
sort: { score: { order: -1 }, _id: 1 },
searchBefore: "<paginationToken>"
}
},
{
$project: {
name: 1,
paginationToken: { $meta: "searchSequenceToken" },
score: { $meta: "searchScore" }
}
}
]
- The first page works correctly.
- Using
searchAfterwith the last document’s token correctly retrieves the next page. - However, when I use
searchBeforewith the first document’s token, it doesn’t return the previous page instead, it returns the same results assearchAfter.
To confirm, if I simply swap searchBefore with searchAfter, I get an identical response.
I’m already passing the correct tokens:
- The first result’s token for
searchBefore - The last result’s token for
searchAfter
What have I Tried
- Verified that the
sortorder and tokens are consistent between queries. - Confirmed the tokens are stored and reused correctly from previous results.
- Tested with both
_idand additional sort fields same behavior.
My Question
Why does $searchBefore return the same direction (results) as $searchAfter instead of the previous page?
Is there something wrong with how I’m using searchBefore or is this a known issue/limitation in Atlas Search pagination?
Please pay attention to update your answer.
Update Your Answer care fully. After saving you can not recover your old answer
When paginating with Atlas Search, the $search stage must have a deterministic and unique sort order.
Otherwise, MongoDB can’t tell exactly where to resume causing the “same results” issue you’re seeing.
{
$search: {
index: "search-index",
text: {
query: "20",
path: "name"
},
sort: {
score: { order: -1 }, // highest score first
_id: { order: 1 } // tie-breaker (unique field)
},
searchBefore: "<paginationToken>"
}
}
Why You Need a Unique Sort Key
If multiple documents share the same score, MongoDB doesn’t know which one comes first unless you also sort by a unique field.
Without that, searchBefore and searchAfter may point to the same group of documents, because the sort order is not strictly defined.
From MongoDB Docs:
“If multiple documents in the results have identical scores, MongoDB doesn’t guarantee ordering.
To guarantee consistent pagination, include a secondary unique sort field.”
The _id field is a perfect choice because it’s always unique and indexed.
Think of it like this:
Imagine you sort students only by marks.
If two students both scored 90, the database doesn’t know which one should come first they could flip order between pages.
But if you add a second unique sort field (like roll number or _id), then pagination becomes consistent.
Common Mistakes
| Mistake | Problem it causes |
|---|---|
| Sorting only by score | Pagination becomes unstable, searchBefore/searchAfter overlap |
| Changing sort order between pages | Tokens become invalid or reversed |
Sorting by non-unique fields (like name) | Duplicates or skipped results |
Recommended Pattern for Reliable Pagination
Always define your sort like this:
sort: {
score: { order: -1 },
_id: { order: 1 }
}
Then:
- Use the last result’s token for
searchAfter(next page) - Use the first result’s token for
searchBefore(previous page) - Reverse the
searchBeforeresult array on the client side
