cursor.sort()
定义
cursor.sort(sort)
重要
mongosh 方法
本页面提供
mongosh
方法的相关信息。这不是特定于语言的驱动程序(例如 Node.js)的文档。如需了解 MongoDB API 驱动程序,请参阅特定语言的 MongoDB 驱动程序文档。
指定查询返回匹配文档的顺序。在从数据库检索任何文档之前,必须对游标应用
sort()
。
兼容性
可以使用 cursor.sort(sort)
查找托管在以下环境中的部署:
MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
sort()
方法具有以下参数:
Parameter | 类型 | 说明 |
---|---|---|
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 Score Metadata Sort
注意
$text
提供自管理(非 Atlas)部署的文本查询功能。对于托管在 MongoDB Atlas 上的数据,MongoDB 提供了一种改进的全文查询解决方案 Atlas Search。
如果您使用 $text
,您可以使用 { $meta: "textScore" }
表达式按相关性分数降序进行排序。
以下示例文档将指定按 "textScore"
元数据排列的降序排序:
db.users.find( { $text: { $search: "operating" } }, { score: { $meta: "textScore" }} ).sort({ score: { $meta: "textScore" } })
"textScore"
元数据按降序排序。
有关详细信息,请参阅 $meta
。
按数组字段排序
当 MongoDB 按数组值字段对文档进行排序时,排序键取决于排序是升序还是降序:
在升序排序中,排序键是数组中的最低值。
在降序排序中,排序键是数组中的最高值。
查询过滤器不影响排序键的选择。
例如,使用以下文档创建 shoes
集合:
db.shoes.insertMany( [ { _id: 'A', sizes: [ 7, 11 ] }, { _id: 'B', sizes: [ 8, 9, 10 ] } ] )
以下查询按 sizes
字段以升序和降序对文档进行排序:
// Ascending sort db.shoes.find().sort( { sizes: 1 } ) // Descending sort db.shoes.find().sort( { sizes: -1 } )
前两个查询均首先返回包含 _id: 'A'
的文档,因为 7
和 11
分别是 sizes
数组中条目中的最小值和最大值。
以下查询查找尺码大于 10 的鞋子,并按鞋子尺码的升序对结果进行排序:
db.shoes.find( { sizes: { $gte: 7 } } ).sort( { sizes: 1 } )
尽管过滤器包含大于 7
的 sizes
条件,但由于查询过滤器不影响排序键的选择,该查询仍会返回带有 _id: 'A'
的文档。
排序和索引使用
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 排序算法。此算法会缓冲基础索引或集合访问迄今为止看到的前 k
项结果(或最后一项,取决于排序顺序)。如果在任何点这些 k
结果的内存占用超过 100 MB,查询就会失败,除非查询指定 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
索引。