In MongoDB, the cursor.sort()
method specifies the order in which the query returns matching documents.
The sort()
method accepts a document that specifies the field to sort, and the sort order. The sort order can be either 1
for ascending or -1
for descending.
You can also specify { $meta: "textScore" }
when doing $text
searches, in order to sort by the computed textScore
metadata in descending order.
Sample Data
Suppose we have a collection called pets
with the following documents:
{ "_id" : 1, "name" : "Wag", "type" : "Dog", "weight" : 20 } { "_id" : 2, "name" : "Bark", "type" : "Dog", "weight" : 10 } { "_id" : 3, "name" : "Meow", "type" : "Cat", "weight" : 7 } { "_id" : 4, "name" : "Scratch", "type" : "Cat", "weight" : 8 } { "_id" : 5, "name" : "Bruce", "type" : "Kangaroo", "weight" : 100 } { "_id" : 6, "name" : "Hop", "type" : "Kangaroo", "weight" : 130 } { "_id" : 7, "name" : "Punch", "type" : "Kangaroo", "weight" : 200 } { "_id" : 8, "name" : "Snap", "type" : "Cat", "weight" : 12 } { "_id" : 9, "name" : "Ruff", "type" : "Dog", "weight" : 30 }
Sort in Ascending Order
To sort in ascending order, we use 1
for the sort order.
Below is an example of a query that uses the $sort
operator to sort that collection by the weight
field in ascending order.
db.pets.find().sort({ weight: 1 })
Result:
{ "_id" : 3, "name" : "Meow", "type" : "Cat", "weight" : 7 } { "_id" : 4, "name" : "Scratch", "type" : "Cat", "weight" : 8 } { "_id" : 2, "name" : "Bark", "type" : "Dog", "weight" : 10 } { "_id" : 8, "name" : "Snap", "type" : "Cat", "weight" : 12 } { "_id" : 1, "name" : "Wag", "type" : "Dog", "weight" : 20 } { "_id" : 9, "name" : "Ruff", "type" : "Dog", "weight" : 30 } { "_id" : 5, "name" : "Bruce", "type" : "Kangaroo", "weight" : 100 } { "_id" : 6, "name" : "Hop", "type" : "Kangaroo", "weight" : 130 } { "_id" : 7, "name" : "Punch", "type" : "Kangaroo", "weight" : 200 }
Sort in Descending Order
To sort in descending order, we use -1
for the sort order.
db.pets.find().sort({ weight: -1 })
Result:
{ "_id" : 7, "name" : "Punch", "type" : "Kangaroo", "weight" : 200 } { "_id" : 6, "name" : "Hop", "type" : "Kangaroo", "weight" : 130 } { "_id" : 5, "name" : "Bruce", "type" : "Kangaroo", "weight" : 100 } { "_id" : 9, "name" : "Ruff", "type" : "Dog", "weight" : 30 } { "_id" : 1, "name" : "Wag", "type" : "Dog", "weight" : 20 } { "_id" : 8, "name" : "Snap", "type" : "Cat", "weight" : 12 } { "_id" : 2, "name" : "Bark", "type" : "Dog", "weight" : 10 } { "_id" : 4, "name" : "Scratch", "type" : "Cat", "weight" : 8 } { "_id" : 3, "name" : "Meow", "type" : "Cat", "weight" : 7 }
Sort by Multiple Fields
To sort by more than one field, separate each field/sort order combo with a comma.
Example
db.pets.find().sort({ type: 1, weight: -1, _id: 1 })
Result:
{ "_id" : 8, "name" : "Snap", "type" : "Cat", "weight" : 12 } { "_id" : 4, "name" : "Scratch", "type" : "Cat", "weight" : 8 } { "_id" : 3, "name" : "Meow", "type" : "Cat", "weight" : 7 } { "_id" : 9, "name" : "Ruff", "type" : "Dog", "weight" : 30 } { "_id" : 1, "name" : "Wag", "type" : "Dog", "weight" : 20 } { "_id" : 2, "name" : "Bark", "type" : "Dog", "weight" : 10 } { "_id" : 7, "name" : "Punch", "type" : "Kangaroo", "weight" : 200 } { "_id" : 6, "name" : "Hop", "type" : "Kangaroo", "weight" : 130 } { "_id" : 5, "name" : "Bruce", "type" : "Kangaroo", "weight" : 100 }
In this example, we sorted by the type
field in ascending order first, then by the weight
field in descending order, then by the _id
field in ascending order.
This means that, if there are multiple pets of the same type, those pets are sorted by their weight
in descending order. If there are multiple pets with both the same type and weight, then those pets are sorted by the _id
field in ascending order. If we hadn’t included the _id
field in the sorting process, then those pets of the same type and weight could appear in any order. This is true each time we run the query. Without having a sort field on a unique field (such as the _id
field), it would be entirely possible (even probable) that the results would come back in a different order each time the query was run.
Sorting Different Types
When comparing values of different BSON types, MongoDB uses the following comparison order, from lowest to highest:
- MinKey (internal type)
- Null
- Numbers (ints, longs, doubles, decimals)
- Symbol, String
- Object
- Array
- BinData
- ObjectId
- Boolean
- Date
- Timestamp
- Regular Expression
- MaxKey (internal type)
Suppose we have a collection called posts with the following documents:
{ "_id" : 1, "title" : "Web", "body" : "Create a funny website with these three easy steps...", "date" : "2021-01-01T00:00:00.000Z" } { "_id" : 2, "title" : "Animals", "body" : "Animals are funny things...", "date" : ISODate("2020-01-01T00:00:00Z") } { "_id" : 3, "title" : "Oceans", "body" : "Oceans are wide and vast, but definitely not funny...", "date" : ISODate("2021-01-01T00:00:00Z") }
Notice that the first date
field contains a date string, whereas the other two documents use a Date object.
Also notice that the date string contains exactly the same date as document 3, and this date is a later date than the date in document 2.
Let’s sort by the date
fields of those documents:
db.posts.find().sort({ date: 1 }).pretty()
Result:
{ "_id" : 1, "title" : "Web", "body" : "Create a funny website with these three easy steps...", "date" : "2021-01-01T00:00:00.000Z" } { "_id" : 2, "title" : "Animals", "body" : "Animals are funny things...", "date" : ISODate("2020-01-01T00:00:00Z") } { "_id" : 3, "title" : "Oceans", "body" : "Oceans are wide and vast, but definitely not funny...", "date" : ISODate("2021-01-01T00:00:00Z") }
In this case we sorted in ascending order, which means earlier dates should come first. However, our first document contains a date string instead of a Date object, and so it came first – even though its date is later than the date in document 2.
Here it is again, but in descending order:
db.posts.find().sort({ date: -1 }).pretty()
Result:
{ "_id" : 3, "title" : "Oceans", "body" : "Oceans are wide and vast, but definitely not funny...", "date" : ISODate("2021-01-01T00:00:00Z") } { "_id" : 2, "title" : "Animals", "body" : "Animals are funny things...", "date" : ISODate("2020-01-01T00:00:00Z") } { "_id" : 1, "title" : "Web", "body" : "Create a funny website with these three easy steps...", "date" : "2021-01-01T00:00:00.000Z" }
Once again, the different data types are ordered separately within themselves.
Text Score Metadata Sort
You can use the { $meta: "textScore" }
argument to sort by descending relevance score when using $text
searches.
Example
db.posts.find(
{ $text: { $search: "funny" } },
{ score: { $meta: "textScore" }}
).sort({ score: { $meta: "textScore" } }
).pretty()
Result:
{ "_id" : 2, "title" : "Animals", "body" : "Animals are funny things...", "date" : ISODate("2020-01-01T00:00:00Z"), "score" : 0.6666666666666666 } { "_id" : 3, "title" : "Oceans", "body" : "Oceans are wide and vast, but definitely not funny...", "date" : ISODate("2021-01-01T00:00:00Z"), "score" : 0.6 } { "_id" : 1, "title" : "Web", "body" : "Create a funny website with these three easy steps...", "date" : "2021-01-01T00:00:00.000Z", "score" : 0.5833333333333334 }
In this example, we sorted by { $meta: "textScore" }
.
From MongoDB 4.4 the line that goes { score: { $meta: "textScore" }}
is optional. Omitting this will omit the score
field from the results. Therefore, we can do the following (from MongoDB 4.4):
db.posts.find(
{ $text: { $search: "funny" } }
).sort({ score: { $meta: "textScore" } }
).pretty()
Result:
{ "_id" : 2, "title" : "Animals", "body" : "Animals are funny things...", "date" : ISODate("2020-01-01T00:00:00Z") } { "_id" : 3, "title" : "Oceans", "body" : "Oceans are wide and vast, but definitely not funny...", "date" : ISODate("2021-01-01T00:00:00Z") } { "_id" : 1, "title" : "Web", "body" : "Create a funny website with these three easy steps...", "date" : "2021-01-01T00:00:00.000Z" }
Doing $text
searches like this requires that we’ve created a text index. If not, an IndexNotFound
error will be returned.
More Information
See the MongoDB documentation for more information.