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或其中一个分片执行流式合并排序。

相关推荐
Arbori_262158 分钟前
oracle常用sql
数据库·sql·oracle
EQ-雪梨蛋花汤43 分钟前
【工具】在 Visual Studio 中使用 Dotfuscator 对“C# 类库(DLL)或应用程序(EXE)”进行混淆
数据库·ide·visual studio
阿ฅ( ̳• ε • ̳)ฅ1 小时前
C#窗体应用程序连接数据库
开发语言·数据库·c#
光军oi3 小时前
Mysql从入门到精通day5————子查询精讲
android·数据库·mysql
qr9j422335 小时前
Django自带的Admin后台中如何获取当前登录用户
数据库·django·sqlite
cherry52305 小时前
【PostgreSQL】【第4章】PostgreSQL的事务
数据库·postgresql
柒月玖.8 小时前
基于AT89C52单片机的轮胎压力监测系统
单片机·嵌入式硬件·mongodb
IT成长日记8 小时前
【MySQL基础】聚合函数从基础使用到高级分组过滤
数据库·mysql·聚合函数
Guarding and trust10 小时前
python系统之综合案例:用python打造智能诗词生成助手
服务器·数据库·python