Sort Atlas Search Results
On this page
Overview
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 the
following field types using the sort
option:
boolean
date
number
(integer, float, and double values)objectId
uuid
string
(indexed as the token type)
You can also sort by the score of the documents in the results and by null values.
Usage
To sort your Atlas Search results, you must do the following:
Create an Atlas Search index on the fields to sort the results by.
To sort on
boolean
,date
,number
,UUID
, andobjectId
fields, use dynamic or static mappings. To sort on string fields, you must use static mappings to index the field as thetoken
type.Create and run your query with the
sort
option against the fields you defined in the index for sorting. To learn more, see Syntax.
Behavior
Sort by Boolean, Date, Numeric, UUID, ObjectId, or String Field
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 UUID values like BinData
. 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. |
Sort by Score And a Unique Field
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. For
example, if you sort the results by a unique field, such as a date field
named lastUpdated
as shown in the following example, Atlas Search returns
results with identical scores in a determined order:
Example
sort: {score: {$meta: "searchScore"}, lastUpdated: 1}
However, if you don't specify a unique field to sort the results by, Atlas Search returns the results sorted by score in descending order. Atlas Search returns results with identical scores or values in an arbitrary order. The following example doesn't sort the results by a unique field.
Example
sort: {score: {$meta: "searchScore"}}
To learn more, see Score the Documents in the Results.
Sort Arrays
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
Sort by Null Values
Atlas Search treats null as equivalent to missing fields and therefore, if you sort by fields that contain null values or is missing in some documents, the ordering of the documents in the results is non-deterministic. When comparing values of different BSON types in sort operations, Atlas Search follows the MongoDB comparison and sort order and considers null values lower than all other supported BSON types.
Sort on Embedded Documents Array Fields
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.
Considerations
Consistency
Atlas Search indexes are eventually consistent, and values returned in results might be different from values used in sorting.
Performance
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.
Scoring
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.
Limitations
You can't sort on fields of embeddedDocuments type.
You can't use the
sort
option with the deprecated knnBeta operator.
Compatibility
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
7.0 and later versions. If you use sort
on sharded Atlas
clusters running MongoDB v5.0 and earlier, Atlas Search returns an error.
Syntax
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 }
Examples
The following examples use the sample_mflix.movies
,
sample_airbnb.listingsAndReview
, or a custom collection named
users
.
Index Definition
The example queries in this page use either the sample_mflix.movies
,
the sample_airbnb.listingsAndReview
, or a custom collection. If you
create the following indexes on these collections, you can run the
sample queries against the indexed fields.
The index definition for the movies
collection specifies the
following:
Index
awards.wins
field as:number
type for sorting and queryingnumberFacet
type for running facet queries
Index
released
field as:date
type for sorting and queryingdateFacet
type for running facet queries
Index
title
field as:token
type for sortingstring
type for querying
1 { 2 "mappings": { 3 "dynamic": true, 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 example queries against the
sample_airbnb.listingsAndReviews
collection use the following
index. The index definition specifies dynamic mappings on the
fields in the collection:
{ "mappings": { "dynamic": true } }
The users
collection contains the following documents:
db.users.insertMany([ { "_id": 0, "a": UUID("1a324de2-e34b-c87e-f2a1-42ce37ad74ed"), "b": "hello", "c": ObjectId("507f1f77bcf86cd799439011") }, { "_id": 1, "a": UUID("3b241101-e2bb-4255-8caf-4136c566a962"), "b": "hello", "c": true }, { "_id": 2, "a": UUID("dee11d4e-63c6-4d90-983c-5c9f1e79e96c"), "b": "hello", "c": "foo" }, { "_id": 3, "b": "hello", "c": UUID("3be11d4e-62cb-4e95-9a3c-5c9f1e56c732") }, { "_id": 4, "a": UUID("d3c12e1c-c36e-25ed-7c3e-1e7f1e53c752"), "b": "hello", "c": null } ])
The index definition for the users
collection specifies the
following:
Dynamically index all the fields except fields named
c
.Statically index field named
c
as the following types for sorting:token
uuid
objectId
boolean
1 { 2 "mappings": { 3 "dynamic": true, 4 "fields": { 5 "c": [ 6 { "type": "token" }, 7 { "type": "uuid" }, 8 { "type": "objectId" }, 9 { "type": "boolean" } 10 ] 11 } 12 } 13 }
For the preceding collection, Atlas Search creates an index named
default
with the specified mappings on the specified fields.
Date Search and Sort
The following query on the sample_mflix.movies
namespace 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 } } ])
Number Search and Sort
The following query on the sample_mflix.movies
namespace 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 } } ])
String Search and Sort
The following query on the sample_mflix.movies
namespace 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" } } } ])
Sort by ObjectId
The following query uses the range operator to search the
the released
field in the sample_mflix.movies
collection for
movies released between 2015-01-01
and 2015-12-31
. It sorts the
results by the _id
field, which contains value of type ObjectId
,
in descending order.
db.movies.aggregate([ { "$search": { "range": { "path": "released", "gt": ISODate("2015-01-01T00:00:00.000Z"), "lt": ISODate("2015-12-31T00:00:00.000Z") }, "sort": { "_id": -1 } } }, { "$limit": 5 }, { "$project": { "_id": 1, "title": 1, "released": 1, "score": { "$meta": "searchScore" } } } ])
Sort by UUID
The following query searches for the term hello
in field b
in
the users
collection. The query sorts the results by field a
,
which contains polymorphic data (to demonstrate the sort order), in
ascending order.
db.users.aggregate([ { "$search": { "text": { "path": "b", "query": "hello" }, "sort": { "a": 1 } } }, { "$project": { "_id": 1, "a": 1, "score": { "$meta": "searchScore" } } } ])
Sort by Null Value
The following query searches field b
for the string hello
in
the users
collection using the text operator. The query
sorts the results by field a
in ascending order.
db.users.aggregate([ { "$search": { "text": { "path": "b", "query": "hello" }, "sort": { "c": 1 } } }, { "$project": { "_id": 1, "c": 1, "score": { "$meta": "searchScore" } } } ])
Atlas Search returns all the documents, but the ordering of documents with
"_id": 2
and "_id": 4
is random because Atlas Search treats
missing and nulls equally when sorting. For more details, see the
MongoDB sort order
for sorting data of different BSON types.
Sort by Boolean
The following query searches the sample_airbnb.listingsAndReviews
collection for properties in Portugal
and sorts the results in
descending order by the boolean
field is_location_exact
.
The query uses the $limit
stage to limit the output to 5
documents. It also uses the $project
stage to omit all
fields except name
, property_type
, address.country
, and
address.location.is_location_exact
in the results.
1 db.listingsAndReviews.aggregate([ 2 { 3 "$search": { 4 "text": { 5 "path": "address.country", 6 "query": "Portugal" 7 }, 8 "sort": { 9 "address.location.is_location_exact": -1, 10 } 11 } 12 }, 13 { 14 "$limit": 5 15 }, 16 { 17 "$project": { 18 "_id": 0, 19 "name": 1, 20 "property_type": 1, 21 "address.country": 1, 22 "address.location.is_location_exact": 1 23 } 24 } 25 ])
In the preceding results, the value of is_location_exact
is true
for the documents because in a descending sort, Atlas Search ranks true
values above false
values. If you do an ascending sort by changing
the value on line 9 of the preceding query to 1
, Atlas Search ranks the
documents with false
values higher than true
values and returns
the following documents:
[ { name: 'Ribeira Charming Duplex', property_type: 'House', address: { country: 'Portugal', location: { is_location_exact: false } } }, { name: 'Be Happy in Porto', property_type: 'Loft', address: { country: 'Portugal', location: { is_location_exact: false } } }, { name: 'Downtown Oporto Inn (room cleaning)', property_type: 'Hostel', address: { country: 'Portugal', location: { is_location_exact: false } } }, { name: 'A Casa Alegre é um apartamento T1.', property_type: 'Apartment', address: { country: 'Portugal', location: { is_location_exact: false } } }, { name: 'FloresRooms 3T', property_type: 'Apartment', address: { country: 'Portugal', location: { is_location_exact: false } } } ]
Compound Search and Sort
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
, andawards.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" } } } ])
Facet Search and Sort
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
, and15
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
, and2015-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 thedocs
output field.Limit the output to
1
document in themeta
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] } } } ])
Sort by Score
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"} } } ])
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
andtitle
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"} } } ])
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
andreleased
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"} } } ])