Docs Menu
Docs Home
/
MongoDB Atlas
/ / / /

Sort Atlas Search Results

On this page

  • Overview
  • Usage
  • Behavior
  • Considerations
  • Limitations
  • Compatibility
  • Syntax
  • Examples
  • Index Definition
  • Date Search and Sort
  • Number Search and Sort
  • String Search and Sort
  • UUID Search and Sort
  • Null Value Search and Sort
  • Compound Search and Sort
  • Facet Search and Sort
  • Sort by Score

Atlas Search allows you to sort the results in ascending or descending order on fields that you define in your Atlas Search index. You can sort by date, number (integer, float, and double values), and string fields indexed as a token type using the sort option. You can also sort by the score of the documents in the results.

Note

Atlas Search sort option is available in sharded clusters only if you run MongoDB v6.0+ or higher.

To sort your Atlas Search results, you must do the following:

  1. Create an Atlas Search index on the fields to sort the results by.

    Atlas Search automatically indexes number and date fields in all indexes created after July 2023 for sorting. For preexisting indexes, you must trigger an index rebuild from the Atlas UI to use any date and number fields in the indexes for sorting. To learn more, see Update Your Existing Index.

    For string fields, you must manually index the field as token type. To learn more, see How to Index String Fields for Efficient Filtering and Sorting.

  2. Create and run your query with the sort option against the fields you defined in the index for sorting. To learn more, see Syntax.

The sort option takes a document that specifies the fields to sort by and the respective sort order. Atlas Search follows the MongoDB comparison order for the supported data types. It treats null and missing values as equivalent in its sort order. To learn more, see non-existent fields.

You can specify the following sort order to sort your results by:

1

Sort in ascending order.

When you sort in ascending order, Atlas Search returns documents with missing values before documents with values.

-1
Sort in descending order.

You can also sort by score in ascending or descending order. The sort option takes a document that specifies the $meta expression, which requires the searchScore value.

Example

Suppose your application allows users to skip to the last page of the search results. The following example sorts the results by score in ascending order so that the document with the lowest score displays at the top of the results:

sort: {score: {$meta: "searchScore", order: 1}}

You can use sort to also ensure that the results have a determined order when multiple documents in the results have identical scores. The following example doesn't sort the results by a unique field.

If you don't specify a unique date or numeric field to sort the results by, Atlas Search defaults to sorting the results by score in descending order and returns results with identical scores in an arbitrary order:

Example

sort: {score: {$meta: "searchScore"}}

However, if you sort the results by a unique date or numeric field, such as a date field named lastUpdated as shown in the following example, Atlas Search uses the value of the specified field to return results with identical scores in a determined order:

Example

sort: {score: {$meta: "searchScore"}, lastUpdated: 1}

To learn more, see Score the Documents in the Results.

Atlas Search flattens the arrays for sorting.

Example

Consider the following array:

[4, [1, [8,5], 9], 2]

Atlas Search flattens the preceding array similar to the following:

4, 1, 8, 5, 9, 2

For an ascending sort, Atlas Search uses 1 to compare the array to other values. For a descending sort, Atlas Search uses 9 to compare the array to other values.

When comparing with elements inside an array:

  • For an ascending sort, Atlas Search compares the smallest elements of the array or performs a less than (<) comparison.

    Example

    Atlas Search sorts results in the following order if you sort by numbers in ascending order:

    -20
    [-3, 12] // <- -3 comes before 5.
    5
    [6, 18] // <- 6 comes after 5.
    13
    14
  • For a descending sort, Atlas Search compares the largest elements of the array or performs a greater than (>) comparison.

    Example

    Atlas Search sorts results in the following order if you sort by numbers in descending order:

    [6, 18] // <- 18 comes before 14.
    14
    13
    [-3, 12] // <- 12 comes after 13.
    5
    -20

To sort the parent documents by an embedded document field, you must do the following:

  • Index the parents of the embedded document child field as the document type.

  • Index the child field with string values within the embedded document as the token type. For child fields with number and date values, enable dynamic mapping to index those fields automatically.

Atlas Search sorts on parent documents only. It doesn't sort the child fields within an array of documents. For an example, see Sort Example.

Atlas Search indexes are eventually consistent, and values returned in results might be different from values used in sorting.

This feature optimizes queries that use $search with $limit as a subsequent stage. If Atlas Search needs to sort all documents in the collection, the response might be slow.

Atlas Search returns scores for all documents in the results. However, you might see higher scoring documents after lower scoring documents because the order of documents in the results is based on the sort criteria unless you explicitly sort by score.

Atlas supports non-sharded sort queries across all major and minor MongoDB 5.0 and later versions. Sharded sort queries are available on all major releases for 6.0 and on all major and minor releases for for 7.0 and later versions. If you use sort on sharded Atlas clusters running MongoDB v5.0 and earlier, Atlas Search returns an error.

sort has the following syntax:

1{
2 "$search": {
3 "index": "<index name>", // optional, defaults to "default"
4 "<operator>": { // such as "text", "compound", or "phrase"
5 <operator-specification>
6 },
7 "sort": {
8 score: {$meta: "searchScore"},
9 "<field-to-sort>": <sort-order>,
10 ...
11 }
12 }
13}

The following examples use the sample_mflix.movies collection in the sample data.

The example queries in this section use the following index. The index definition for the collection specifies the following:

  • Index awards.wins field as:

    • number type for sorting and querying

    • numberFacet type for running facet queries

  • Index released field as:

    • date type for sorting and querying

    • dateFacet type for running facet queries

  • Index title field as:

    • token type for sorting

    • string type for querying

1{
2 "mappings": {
3 "dynamic": false,
4 "fields": {
5 "awards": {
6 "dynamic": false,
7 "fields": {
8 "wins": [
9 {
10 "type": "number"
11 },
12 {
13 "type": "numberFacet"
14 }
15 ]
16 },
17 "type": "document"
18 },
19 "released": [
20 {
21 "type": "date"
22 },
23 {
24 "type": "dateFacet"
25 }
26 ],
27 "title": [{
28 "type": "token"
29 }, {
30 "type": "string"
31 }]
32 }
33 }
34}

For the preceding index definition, Atlas Search creates an index named default with static mappings on the specified fields.

The following query uses the $search stage to do the following:

  • Search for movies released between 01 January, 2010 and 01, January, 2015 using the range operator.

  • Sort the results in descending order of released date using the sort option.

The query uses the $limit stage to limit the output to 5 documents. It also uses the $project stage to omit all fields except title and released in the results.

db.movies.aggregate([
{
"$search": {
"range": {
"path": "released",
"gt": ISODate("2010-01-01T00:00:00.000Z"),
"lt": ISODate("2015-01-01T00:00:00.000Z")
},
"sort": {
"released": -1
}
}
},
{
"$limit": 5
},
{
"$project": {
"_id": 0,
"title": 1,
"released": 1
}
}
])
[
{
title: 'The Gambler',
released: ISODate("2014-12-31T00:00:00.000Z")
},
{
title: 'Cold in July',
released: ISODate("2014-12-31T00:00:00.000Z")
},
{
title: 'Force Majeure',
released: ISODate("2014-12-30T00:00:00.000Z")
},
{
title: 'LFO',
released: ISODate("2014-12-27T00:00:00.000Z")
},
{
title: 'The Water Diviner',
released: ISODate("2014-12-26T00:00:00.000Z")
}
]

The following query uses the $search stage to do the following:

  • Search for movies that have won awards.

  • Sort the results in descending order using sort option.

The query uses the $limit stage to limit the output to 5 documents. It also uses the $project stage to omit all fields except title and awards.wins in the results.

db.movies.aggregate([
{
"$search": {
"range": {
"path": "awards.wins",
"gt": 3
},
"sort": {
"awards.wins": -1
}
}
},
{
"$limit": 5
},
{
"$project": {
"_id": 0,
"title": 1,
"awards.wins": 1
}
}
])
[
{ title: '12 Years a Slave', awards: { wins: 267 } },
{ title: 'Gravity', awards: { wins: 231 } },
{ title: 'Gravity', awards: { wins: 231 } },
{
title: 'Birdman: Or (The Unexpected Virtue of Ignorance)',
awards: { wins: 210 }
},
{ title: 'Boyhood', awards: { wins: 185 } },
]

The following query uses the $search stage to do the following:

  • Search for movies that have the term country in the title.

  • Sort the results in ascending order using sort option.

The query uses the $limit stage to limit the output to 5 documents. It also uses the $project stage to do the following:

  • Omit all fields except title in the results.

  • Add a field named score.

db.movies.aggregate([
{
"$search": {
"text": {
"path": "title",
"query": "country"
},
"sort": {
"title": 1
}
}
},
{
"$limit": 5
},
{
"$project": {
"_id": 0,
"title": 1,
"score": { "$meta": "searchScore" }
}
}
])
[
{ title: 'A Country Called Home', score: 2.536633253097534 },
{ title: 'A Month in the Country', score: 2.258953094482422 },
{ title: 'A Quiet Place in the Country', score: 2.0360684394836426 },
{ title: 'A Sunday in the Country', score: 2.258953094482422 },
{ title: 'Another Country', score: 3.3635599613189697 }
]

UUID sorting follows the behavior of MongoDB comparison order.

db.users.insertMany([
{
"_id": 0,
"a": UUID("00000000-1111-2222-3333-444444444444"),
"b": "hello"
},
{
"_id": 1,
"a": "foo",
"b": "hello"
},
{
"_id": 2,
"a": 5,
"b": "hello"
},
{
"_id": 3,
"b": "hello"
}
])
{
$search: {
"text": {
"path": "b",
"query": "hello"
},
"sort": {
"a": 1
}
}
}
"results": [
{
"_id": 3 // missing
},
{
"_id": 2 // number
},
{
"_id": 1 // string
},
{
"_id": 0 // binary data (UUID)
}
]

Fields which contain null values that are used for sorting will treat null as equivalent to missing fields. For example, given the following documents and query, the ordering between documents 2 and 3 is non-deterministic, since the MQL sort order treats missing and nulls equally when sorting.

db.users.insertMany([
{
"_id": 0,
"a": 20,
"b": "hello"
},
{
"_id": 1,
"a": 10,
"b": "hello"
},
{
"_id": 2,
"a": null,
"b": "hello"
},
{
"_id": 3,
"b": "hello"
}
])
{
$search: {
"text": {
"path": "b",
"query": "hello"
},
"sort": {
"a": 1
}
}
}
"results": [
{
"_id": 3
},
{
"_id": 2
},
{
"_id": 1
},
{
"_id": 0
}
]

The following query uses the $search stage to do the following:

  • Search for movies that have the term dance in the title, with a preference for movies that have won 2 or more awards and were released after 01 January, 1990.

  • Sort the results by the number of awards in descending order, then by the movie title in ascending order, and then by the release date in descending order.

The query uses the $limit stage to limit the output to 10 documents. It also uses the $project stage to do the following:

  • Omit all fields except title, released, and awards.wins in the results.

  • Add a field named score.

db.movies.aggregate([
{
"$search": {
"compound": {
"must": [{
"text": {
"path": "title",
"query": "dance"
}
}],
"should": [{
"range": {
"path": "awards.wins",
"gte": 2
}
}, {
"range": {
"path": "released",
"gte": ISODate("1990-01-01T00:00:00.000Z")
}
}]
},
"sort": {
"awards.wins": -1,
"title": 1,
"released": -1
}
}
},
{
"$limit": 10
},
{
"$project": {
"_id": 0,
"title": 1,
"released": 1,
"awards.wins": 1,
"score": { "$meta": "searchScore" }
}
}
])
[
{
title: 'Shall We Dance?',
released: ISODate("1997-07-11T00:00:00.000Z"),
awards: { wins: 57 },
score: 4.9811458587646484
},
{
title: 'Shall We Dance?',
released: ISODate("1997-07-11T00:00:00.000Z"),
awards: { wins: 57 },
score: 4.9811458587646484
},
{
title: 'War Dance',
released: ISODate("2008-11-01T00:00:00.000Z"),
awards: { wins: 11 },
score: 5.466421127319336
},
{
title: 'Dance with the Devil',
released: ISODate("1997-10-31T00:00:00.000Z"),
awards: { wins: 6 },
score: 4.615056037902832
},
{
title: 'Save the Last Dance',
released: ISODate("2001-01-12T00:00:00.000Z"),
awards: { wins: 6 },
score: 4.615056037902832
},
{
title: 'Dance with a Stranger',
released: ISODate("1985-08-09T00:00:00.000Z"),
awards: { wins: 4 },
score: 3.615056037902832
},
{
title: 'The Baby Dance',
released: ISODate("1998-08-23T00:00:00.000Z"),
awards: { wins: 4 },
score: 4.981145858764648
},
{
title: 'Three-Step Dance',
released: ISODate("2004-02-19T00:00:00.000Z"),
awards: { wins: 4 },
score: 4.981145858764648
},
{
title: "Cats Don't Dance",
released: ISODate("1997-03-26T00:00:00.000Z"),
awards: { wins: 3 },
score: 4.981145858764648
},
{
title: 'Dance Me Outside',
released: ISODate("1995-03-10T00:00:00.000Z"),
awards: { wins: 3 },
score: 4.981145858764648
}
]

The following query uses the $search stage to do the following:

  • Search for movies released between 01 January, 2010 and 01, January, 2015 using the range operator.

  • Get a count of the number of movies that won 1, 5, 10, and 15 awards.

  • Get a count of the number of movies released on 2010-01-01, 2011-01-01, 2012-01-01, 2013-01-01, 2014-01-01, and 2015-01-01.

  • Sort the results in descending order of released date using the sort option.

The query uses the $limit stage to do the following:

  • Limit the output to 5 documents in the docs output field.

  • Limit the output to 1 document in the meta output field.

It uses the $project stage to omit all fields except the awards.wins, released, and title fields.

It also uses the $replaceWith stage to include the metadata results stored in the $$SEARCH_META variable in the meta output field and the $set stage to add the meta field to the results.

db.movies.aggregate([
{
"$search": {
"facet": {
"operator": {
"range": {
"path": "released",
"gt": ISODate("2010-01-01T00:00:00.000Z"),
"lt": ISODate("2015-01-01T00:00:00.000Z")
}
},
"facets": {
"awardsFacet": {
"type": "number",
"path": "awards.wins",
"boundaries" : [1,5,10,15]
},
"releasedFacet" : {
"type" : "date",
"path" : "released",
"boundaries" : [ISODate("2010-01-01T00:00:00.000Z"), ISODate("2011-01-01T00:00:00.000Z"), ISODate("2012-01-01T00:00:00.000Z"), ISODate("2013-01-01T00:00:00.000Z"), ISODate("2014-01-01T00:00:00.000Z"), ISODate("2015-01-01T00:00:00.000Z")]
}
}
},
"sort": {
"released": -1
}
}
},
{
"$facet": {
"docs": [
{ "$limit": 5 },
{ "$project":
{
"_id": 0,
"title": 1,
"released": 1,
"awards.wins": 1
}
}
],
"meta": [
{"$replaceWith": "$$SEARCH_META"},
{"$limit": 1}
]
}
},
{
"$set": {
"meta": {
"$arrayElemAt": ["$meta", 0]
}
}
}
])
[
{
docs: [
{
title: 'The Gambler',
released: ISODate("2014-12-31T00:00:00.000Z"),
awards: { wins: 7 }
},
{
title: 'Cold in July',
released: ISODate("2014-12-31T00:00:00.000Z"),
awards: { wins: 1 }
},
{
title: 'Force Majeure',
released: ISODate("2014-12-30T00:00:00.000Z"),
awards: { wins: 31 }
},
{
title: 'LFO',
released: ISODate("2014-12-27T00:00:00.000Z"),
awards: { wins: 3 }
},
{
title: 'The Water Diviner',
released: ISODate("2014-12-26T00:00:00.000Z"),
awards: { wins: 8 }
}
],
meta: {
count: { lowerBound: Long("4821") },
facet: {
releasedFacet: {
buckets: [
{
_id: ISODate("2010-01-01T00:00:00.000Z"),
count: Long("857")
},
{
_id: ISODate("2011-01-01T00:00:00.000Z"),
count: Long("909")
},
{
_id: ISODate("2012-01-01T00:00:00.000Z"),
count: Long("903")
},
{
_id: ISODate("2013-01-01T00:00:00.000Z"),
count: Long("1063")
},
{
_id: ISODate("2014-01-01T00:00:00.000Z"),
count: Long("1089")
}
]
},
awardsFacet: {
buckets: [
{ _id: 1, count: Long("2330") },
{ _id: 5, count: Long("604") },
{ _id: 10, count: Long("233") }
]
}
}
}
}
}
]

The following examples demonstrate how to sort the results by the score of the documents in the results. The examples demonstrate how to perform the following actions:

  • Retrieve the lowest scoring documents first by sorting the results in ascending order.

  • Sort the results by score in descending order and for results with identical scores, sort arbitrarily.

  • Sort the results by score and for results with identical scores, sort using a unique field.

The following query uses the $search stage to perform the following actions:

  • Search for movies that have the term story in the title.

  • Sort the results by score in ascending order.

The query uses the $limit stage to limit the output to 5 documents. It also uses the $project stage to perform the following actions:

  • Omit all fields except title in the results.

  • Add a field named score.

db.movies.aggregate([
{
"$search": {
"text": {
"path": "title",
"query": "story"
},
"sort": {score: {$meta: "searchScore", order: 1}}
}
},
{
"$limit": 5
},
{
"$project": {
"_id": 0,
"title": 1,
"score": {$meta: "searchScore"}
}
}
])
[
{
title: 'Do You Believe in Miracles? The Story of the 1980 U.S. Hockey Team',
score: 0.8674521446228027
},
{
title: 'Once in a Lifetime: The Extraordinary Story of the New York Cosmos',
score: 0.9212141036987305
},
{
title: 'The Source: The Story of the Beats and the Beat Generation',
score: 0.9820802211761475
},
{
title: 'If These Knishes Could Talk: The Story of the NY Accent',
score: 0.9820802211761475
},
{
title: 'Dream Deceivers: The Story Behind James Vance vs. Judas Priest',
score: 1.051558256149292
}
]

The following query uses the $search stage to perform the following actions:

  • Search for movies that have the term summer in the title.

  • Sort the results by score in descending order and for results with identical scores, sort arbitrarily.

The query uses the $limit stage to limit the output to 5 documents. It also uses the $project stage to perform the following actions:

  • Omit all fields except _id and title in the results.

  • Add a field named score.

db.movies.aggregate([
{
"$search": {
"text": {
"path": "title",
"query": "summer"
},
"sort": {score: {$meta: "searchScore"}}
}
},
{
"$limit": 5
},
{
"$project": {
"_id": 1,
"title": 1,
"score": {$meta: "searchScore"}
}
}
])
[
{
_id: ObjectId("573a1398f29313caabcea21e"),
title: 'Summer',
score: 3.5844719409942627
},
{
_id: ObjectId("573a13a6f29313caabd18eca"),
title: 'Summer Things',
score: 3.000213623046875
},
{
_id: ObjectId("573a13b8f29313caabd4c1d0"),
title: 'Summer Palace',
score: 3.000213623046875
},
{
_id: ObjectId("573a1394f29313caabcde8e8"),
title: 'Summer Stock',
score: 3.000213623046875
},
{
_id: ObjectId("573a13acf29313caabd284fa"),
title: 'Wolf Summer',
score: 3.000213623046875
}
]

The following query uses the $search stage to perform the following actions:

  • Search for movies that have the term prince in the title.

  • Sort the results first by score and then by the value of the released field in ascending order for results with identical scores.

The query uses the $limit stage to limit the output to 5 documents. It also uses the $project stage to perform the following actions:

  • Omit all fields except title and released in the results.

  • Add a field named score.

db.movies.aggregate([
{
"$search": {
"text": {
"path": "title",
"query": "prince"
},
"sort": {score: {$meta: "searchScore"}, "released": 1}
}
},
{
"$limit": 5
},
{
"$project": {
"_id": 0,
"title": 1,
"released": 1,
"score": {$meta: "searchScore"}
}
}
])
[
{
title: 'Prince',
released: ISODate("2015-08-14T00:00:00.000Z"),
score: 4.168826103210449
},
{
title: 'Prince Avalanche',
released: ISODate("2013-09-19T00:00:00.000Z"),
score: 3.4893198013305664
},
{
title: 'The Prince',
released: ISODate("2014-08-22T00:00:00.000Z"),
score: 3.4893198013305664
},
{
title: 'Prince of Foxes',
released: ISODate("1949-12-23T00:00:00.000Z"),
score: 3.0002830028533936
},
{
title: 'The Oil Prince',
released: ISODate("1966-01-01T00:00:00.000Z"),
score: 3.0002830028533936
}
]

Back

5. Define Additional Search Options

Next

2. Parallelize Query Execution