Docs 主页 → 开发应用程序 → MongoDB Manual
cursor.sort()
定义
兼容性
可以使用 cursor.sort(sort)
查找托管在以下环境中的部署:
MongoDB Atlas :用于在云中部署 MongoDB 的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
sort()
方法具有以下参数:
范围 | 类型 | 说明 |
---|---|---|
sort | 文档 | 定义结果集排序顺序的文档。 |
sort
参数包含字段和值对,格式如下:
{ field: value }
排序文档可以指定对现有字段进行升序或降序排序,或者对文本得分元数据进行排序。
行为
限制
您最多可以对 32 个键进行排序。
排序一致性
MongoDB 不按特定顺序将文档存储在集合中。对包含重复值的字段进行排序时,可能会以任何顺序返回包含这些值的文档。
如果需要一致的排序顺序,请在排序中至少纳入一个包含唯一值的字段。最简单方法是在排序查询中纳入 _id
字段。
考虑以下restaurant
集合:
db.restaurants.insertMany( [ { "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan"}, { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens"}, { "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn"}, { "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan"}, { "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn"}, ] );
以下命令使用sort()
方法对borough
字段进行排序:
db.restaurants.find().sort( { "borough": 1 } )
在此示例中,排序顺序可能不一致,因为 borough
字段包含 Manhattan
和 Brooklyn
的重复值。文档按 borough
的字母顺序返回,但具有 borough
的重复值的文档的顺序在多次执行同一排序中可能不相同。例如,以下是上述命令两次不同执行的结果:
{ "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn" } { "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn" } { "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan" } { "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan" } { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens" } { "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn" } { "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn" } { "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan" } { "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan" } { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens" }
虽然 borough
的值仍按字母顺序排序,但包含 borough
重复值的文档(即 Manhattan
和 Brooklyn
)的顺序不同。
要实现一致的排序,请将仅包含唯一值的字段添加到排序中。以下命令使用sort()
方法对borough
字段和_id
字段进行排序:
db.restaurants.find().sort( { "borough": 1, "_id": 1 } )
由于 _id
字段始终保证包含唯一值,因此在同一排序的多次执行中返回的排序顺序将始终相同。
升序/降序排序
在排序参数中指定要排序的一个或多个字段,并指定值 1
或 -1
以分别指定升序或降序排序。
以下操作首先按 age
字段以降序对文档进行排序,然后按 posts
字段以升序对文档进行排序:
db.users.find({ }).sort( { age : -1, posts: 1 } )
在排序操作中比较不同 BSON 类型的值时,MongoDB 使用以下从低到高的比较顺序:
MinKey(内部类型)
null
数值(int、long、double、decimal)
符号,字符串
对象
阵列
BinData
ObjectId
布尔
Date
时间戳
正则表达式
MaxKey(内部类型)
有关特定类型的比较/排序顺序的详细信息,请参阅比较/排序顺序。
文本分数元数据排序
对于 $text
搜索,您可以使用 { $meta: "textScore" }
表达式按相关性分数降序进行排序。
以下示例文档将指定按 "textScore"
元数据排列的降序排序:
db.users.find( { $text: { $search: "operating" } }, { score: { $meta: "textScore" }} ).sort({ score: { $meta: "textScore" } })
"textScore"
元数据按降序排序。
有关详细信息,请参阅 $meta
。
排序和索引使用
MongoDB 可从包含排序字段的索引中获取排序操作的结果。如果此排序使用与查询谓词相同的索引,MongoDB 则可能会使用多个索引支持排序操作。
如果 MongoDB 无法使用一个或多个索引来获取排序顺序,则 MongoDB 必须对数据执行阻塞排序操作。阻塞排序表示 MongoDB 必须在返回结果之前消耗并处理排序的所有输入文档。阻塞排序不会阻塞对集合或数据库的并发操作。
使用索引的排序操作通常比阻塞排序性能更好。有关创建索引以支持排序操作的更多信息,请参阅使用索引对查询结果进行排序。
如果 MongoDB 需要使用超过100 MB 的系统内存来执行阻塞排序操作,则 MongoDB 将返回错误,除非查询指定cursor.allowDiskUse()
。 allowDiskUse()
允许 MongoDB 在处理阻塞排序操作时使用磁盘上的临时文件来存储超过100 MB 系统内存限制的数据。
要检查 MongoDB 是否必须执行阻塞排序,请在查询中添加 cursor.explain()
并检查解释结果。如果查询计划包含 SORT
阶段,则 MongoDB 必须在 100 MB 内存限制下执行阻塞排序操作。
要防止阻塞排序消耗过多内存:
创建索引以支持排序操作。请参阅使用索引对查询结果进行排序以了解更多信息和示例。
通过使用
cursor.limit()
和cursor.sort()
来限制要排序的数据量。有关更多信息和示例,请参阅限制结果。
提示
另请参阅:
限制结果
您可以将sort()
与limit()
结合使用,返回第一个(按排序顺序) k
文档,其中k
是指定的限制。
如果 MongoDB 无法通过索引扫描获得排序顺序,则 MongoDB 使用 算法 top-k。此算法会缓冲底层索引或collection访问到目前为止看到的前k
个结果(或最后一个,取决于排序顺序)。如果在任何时候这些k
结果的内存占用超过100兆字节,则查询将失败,除非查询指定cursor.allowDiskUse()
。
提示
另请参阅:
与投影交互
当一组结果同时进行排序和投影时,MongoDB 查询引擎始终会先应用排序操作。
举例
集合 orders
包含以下文档:
{ _id: 1, item: { category: "cake", type: "chiffon" }, amount: 10 } { _id: 2, item: { category: "cookies", type: "chocolate chip" }, amount: 50 } { _id: 3, item: { category: "cookies", type: "chocolate chip" }, amount: 15 } { _id: 4, item: { category: "cake", type: "lemon" }, amount: 30 } { _id: 5, item: { category: "cake", type: "carrot" }, amount: 20 } { _id: 6, item: { category: "brownies", type: "blondie" }, amount: 10 }
以下查询返回 orders
集合中的所有文档,但不会指定排序顺序:
db.orders.find()
此查询将以不确定的顺序返回文档:
{ "_id" : 1, "item" : { "category" : "cake", "type" : "chiffon" }, "amount" : 10 } { "_id" : 2, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 50 } { "_id" : 3, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 15 } { "_id" : 4, "item" : { "category" : "cake", "type" : "lemon" }, "amount" : 30 } { "_id" : 5, "item" : { "category" : "cake", "type" : "carrot" }, "amount" : 20 } { "_id" : 6, "item" : { "category" : "brownies", "type" : "blondie" }, "amount" : 10 }
以下查询指定对 amount
字段进行降序排序。
db.orders.find().sort( { amount: -1 } )
此查询返回以下文档,按 amount
的降序排列:
{ "_id" : 2, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 50 } { "_id" : 4, "item" : { "category" : "cake", "type" : "lemon" }, "amount" : 30 } { "_id" : 5, "item" : { "category" : "cake", "type" : "carrot" }, "amount" : 20 } { "_id" : 3, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 15 } { "_id" : 1, "item" : { "category" : "cake", "type" : "chiffon" }, "amount" : 10 } { "_id" : 6, "item" : { "category" : "brownies", "type" : "blondie" }, "amount" : 10 }
以下查询使用嵌入式文档 item
中的字段指定排序顺序。查询首先按 category
字段升序排序,然后在每个 category
中按 type
字段升序排序。
db.orders.find().sort( { "item.category": 1, "item.type": 1 } )
此查询将返回以下文档,并先按 category
字段进行排序,然后在每个类别中按 type
字段进行排序:
{ "_id" : 6, "item" : { "category" : "brownies", "type" : "blondie" }, "amount" : 10 } { "_id" : 5, "item" : { "category" : "cake", "type" : "carrot" }, "amount" : 20 } { "_id" : 1, "item" : { "category" : "cake", "type" : "chiffon" }, "amount" : 10 } { "_id" : 4, "item" : { "category" : "cake", "type" : "lemon" }, "amount" : 30 } { "_id" : 2, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 50 } { "_id" : 3, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 15 }
按自然顺序返回
$natural
参数会根据项目在数据库中的自然顺序来返回项目。此排序是一项内部实现功能,您不应依赖于文档的任何特定排序。
索引使用
包含按 $natural
排序的查询不使用索引来满足查询谓词,但以下情况除外:如果查询谓词是 _id
字段 { _id: <value> }
上的相等条件,则按 $natural
排序的查询可以使用 _id
索引。