MongoDB聚合: $sort

聚合的$sort阶段对所有输入文件进行排序,并按排序顺序返回管道。

语法

js 复制代码
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }

$sort阶段参数为一个文档,该文档指定了要排序的字段和相应的排序顺序。<sort order>为下列值之一:

含义
1 正序(由小到大)
2 逆序(由大到小)
{ $meta: "textScore" } 根据textScore的计算结果按照由大到小排序

如果对多个字段进行排序,排序顺序将从左到右进行计算。例如,在上面的表格中,文档首先按<field1>排序。然后,具有相同<field1>值的文档再按<field2>排序。

用法

需要注意:排序最多支持32个键

排序的一致性问题

MongoDB不会按特定顺序对集合中的文档排序,因此,对于有重复值的字段进行排序时,返回的顺序可能会不一样,也就是说排序是不稳定的。如果希望排序顺序一致,至少要在排序字段中包含一个唯一字段,最简单的方法就是排序时加上_id字段。

如下面的集合restaurant

js 复制代码
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"},
] )

使用$sortborough字段进行排序:

js 复制代码
db.restaurants.aggregate(
   [
     { $sort : { borough : 1 } }
   ]
)

在这个例子中,多次排序结果的顺序就可能会有不同,因为borough字段包含ManhattanBrooklyn的重复值,文档按照borough的字母顺序返回,在多次执行同一排序时,borough值重复的文档的顺序就可能不同,下面就是执行两次命令不同的结果:

第一次:

json 复制代码
{ "_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" }

第二次:

json 复制代码
{ "_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的值仍按字母顺序排序,但包含重复区值(即ManhattanBrooklyn)的文档的顺序却不一样。

要实现一致的排序,可在排序中添加一个只包含唯一值的字段。以下命令使用
$sort阶段对borough_id字段进行排序:

js 复制代码
db.restaurants.aggregate(
   [
     { $sort : { borough : 1, _id: 1 } }
   ]
)

由于_id字段是唯一值,因此在多次执行同一排序时,返回的排序顺序总是相同的。

举例

升序/降序排序

对于要排序的一个或多个字段,将排序顺序设为1-1,分别指定升序或降序排序,如下所示:

js 复制代码
db.users.aggregate(
   [
     { $sort : { age : -1, posts: 1 } }
   ]
)

该操作将用户集合中的文档按照age字段降序排序,然后按照posts字段的值升序排序。

在排序操作中比较不同BSON类型的值时,MongoDB使用以下从低到高的比较顺序:

  1. MinKey (internal type)
  2. Null
  3. Numbers (ints, longs, doubles, decimals)
  4. Symbol, String
  5. Object
  6. Array
  7. BinData
  8. ObjectId
  9. Boolean
  10. Date
  11. Timestamp
  12. Regular Expression
  13. MaxKey (internal type)

文本得分元数据排序

对于包含$text搜索的管道,可以使用{ $meta: "textScore" }表达式按相关性得分降序排序。在{ <sort-key> }文档中,将{ $meta: "textScore" }表达式设置为任意字段名称。查询系统将忽略字段名称。如:

js 复制代码
db.users.aggregate(
   [
     { $match: { $text: { $search: "operating" } } },
     { $sort: { score: { $meta: "textScore" }, posts: -1 } }
   ]
)

此操作使用$text操作符匹配文档,然后首先按"textScore"元数据降序排序,然后按帖子字段降序排序。查询系统会忽略排序文档中的分数字段名称。在这个流程中,"textScore"元数据不包含在预测中,也不会作为匹配文档的一部分返回。

$sort操作和内存

$sort + $limit 内存优化

$sort$limit之前,且中间没有修改文档数量的阶段时,优化器可以将$limit合并到$sort这样,$sort操作在进行过程中只保留前n个结果(其中n是指定的限制),并确保MongoDB只需在内存中存储n个条目。当allowDiskUsetruen项超过聚合内存限制时,该优化仍然适用。不同版本之间的优化可能会有变化。

$sort和内存限制

$sort受100M内存使用限制,但如果需要,可以将临时文件写入磁盘。从 MongoDB 6.0开始,需要超过100MB内存才能执行的管道阶段默认会将临时文件写入磁盘。在MongoDB早期版本中,要启用此行为,必须传递{ allowDiskUse: true }

单个findaggregate命令可以通过以下任一方式覆盖allowDiskUseByDefault参数:

  • allowDiskUseByDefault设置为false时,使用{ allowDiskUse: true}可以把临时文件写入磁盘

  • allowDiskUseByDefault设置为true时,使用{ allowDiskUse: false}将禁止把临时文件写入磁盘。

$sort和性能

如果$sort用于管道的第一阶段,或仅在$match阶段之前使用,则可以利用索引的优势。

当使用$sort时,每个分片会使用可用的索引对文档进行排序,然后,mongos或其中一个分片执行流式合并排序。

相关推荐
吳所畏惧5 分钟前
宝塔面板Redis密码修改指南:SSH命令修改 vs 面板UI界面修改,哪个更靠谱?
运维·服务器·数据库·redis·缓存·ssh
DFT计算杂谈8 分钟前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
HPFBoy16 分钟前
log4net 数据库存日志正确配置
数据库
liuxiaowei343 分钟前
【绝版教程】新版MySQL DBA高级实战进阶班 MySQL8.0 姜承尧-腾讯数据库总监
数据库·mysql·dba
破碎的南瓜1 小时前
sqli--sql注入过关笔记(1,2,3,4,5,9)
数据库·笔记·sql
吠品3 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
SelectDB3 小时前
Apache Doris Variant 动态 JSON 实战教程:从建表到跑通 100M Agent 日志查询
数据库
sg_knight3 小时前
MySQL 存储过程详解:从入门到实战
android·数据库·mysql·database·dba·关系型数据库·db
星空露珠4 小时前
28种颜色对应名称,
开发语言·数据库·算法·游戏·lua
踏月的造梦星球5 小时前
DM8 DSC 单机双实例部署
运维·开发语言·数据库