LogIn
I don't have account.

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 searchAfter with the last document’s token correctly retrieves the next page.
  • However, when I use searchBefore with the first document’s token, it doesn’t return the previous page instead, it returns the same results as searchAfter.

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 sort order and tokens are consistent between queries.
  • Confirmed the tokens are stored and reused correctly from previous results.
  • Tested with both _id and 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

Carefully Update Your 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

MistakeProblem it causes
Sorting only by scorePagination becomes unstable, searchBefore/searchAfter overlap
Changing sort order between pagesTokens 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 searchBefore result array on the client side