Docs 主页 → 开发应用程序 → MongoDB Manual
$sort(聚合)
定义
兼容性
可以使用 $sort
查找托管在以下环境中的部署:
MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
$sort
阶段具有以下原型形式:
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
$sort
接受一个文档,其中指定要作为排序依据的字段以及相应的排序顺序。 <sort order>
可以是以下值之一:
值 | 说明 |
---|---|
1 | 升序排序。 |
-1 | 降序排序。 |
{ $meta: "textScore" } |
|
如果对多个字段进行排序,则按从左到右的顺序进行排序。例如,在上面的表单中,文档首先按 <field1>
排序。然后,具有相同 <field1>
值的文档将按 <field2>
进一步排序。
行为
限制
您最多可以对 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.aggregate( [ { $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.aggregate( [ { $sort : { borough : 1, _id: 1 } } ] )
由于 _id
字段始终保证包含唯一值,因此在同一排序的多次执行中返回的排序顺序将始终相同。
举例
升序/降序排序
对于要作为排序依据的一个或多个字段,请将排序顺序设置为 1
或 -1
以分别指定升序或降序,如下例所示:
db.users.aggregate( [ { $sort : { age : -1, posts: 1 } } ] )
此操作对 users
集合中的文档进行排序,先根据 age
字段降序排列,再根据 posts
字段中的值升序排序。
在排序操作中比较不同 BSON 类型的值时,MongoDB 使用以下从低到高的比较顺序:
MinKey(内部类型)
null
数值(int、long、double、decimal)
符号,字符串
对象
阵列
BinData
ObjectId
布尔
Date
时间戳
正则表达式
MaxKey(内部类型)
有关特定类型的比较/排序顺序的详细信息,请参阅比较/排序顺序。
文本分数元数据排序
对于包含 $text
搜索的管道,您可以使用 { $meta: "textScore"
}
表达式按相关性分数降序排序。在 { <sort-key> }
文档中,将 { $meta: "textScore" }
表达式设置为任意字段名称。查询系统将忽略该字段名称。例如:
db.users.aggregate( [ { $match: { $text: { $search: "operating" } } }, { $sort: { score: { $meta: "textScore" }, posts: -1 } } ] )
此操作使用 $text
操作符匹配文档,然后首先按 "textScore"
元数据降序排序,然后按 posts
字段降序排序。 查询系统会忽略排序文档中的score
字段名称。在此管道中, "textScore"
元数据不包含在投影中,也不作为匹配文档的一部分返回。有关更多信息,请参见$meta
。
$sort
操作符和内存
$sort
+ $limit
内存优化
当$sort
在$limit
之前并且没有修改文档数量的中间阶段时,优化器可以将$limit
合并到$sort
中。这允许$sort
操作在推进时仅维护前n
结果(其中n
是指定的限制),并确保 MongoDB 只需在内存中存储n
个项目。当allowDiskUse
为true
并且n
项超过聚合内存限制时,此优化仍然适用。
优化可能因版本而异。
$sort
和内存限制
$sort
受 100 MB 内存限制,但如果需要额外空间,则可以将临时文件写入磁盘。
从 MongoDB 6.0 开始,需要 100 MB 以上内存容量的管道阶段默认将临时文件写入磁盘。在 MongoDB 的早期版本中,您必须将 { allowDiskUse: true }
传递给单个 find
和 aggregate
命令才能启用此行为。
单个 find
和 aggregate
命令可以通过以下任一方式覆盖 allowDiskUseByDefault
参数:
使用
{ allowDiskUse: true }
以允许在allowDiskUseByDefault
设置为false
时将临时文件写入磁盘使用
{ allowDiskUse: false }
以禁止在allowDiskUseByDefault
设置为true
时将临时文件写入磁盘
提示
另请参阅:
$sort
操作符和性能
$sort
如果索引用在管道的第一阶段或其前面仅是 阶段,则$match
操作符可以利用索引。
当您在分片集群上使用$sort
时,每个分片都会使用可用的索引对其结果文档进行排序。然后, mongos
或其中一个分片执行流式合并排序。