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

相关推荐
The_Ticker22 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
Elastic 中国社区官方博客28 分钟前
Elasticsearch 开放推理 API 增加了对 IBM watsonx.ai Slate 嵌入模型的支持
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
企鹅侠客32 分钟前
ETCD调优
数据库·etcd
Json_1817901448038 分钟前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
煎饼小狗1 小时前
Redis五大基本类型——Zset有序集合命令详解(命令用法详解+思维导图详解)
数据库·redis·缓存
永乐春秋1 小时前
WEB-通用漏洞&SQL注入&CTF&二次&堆叠&DNS带外
数据库·sql
打鱼又晒网2 小时前
【MySQL】数据库精细化讲解:内置函数知识穿透与深度学习解析
数据库·mysql
大白要努力!2 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
tatasix3 小时前
MySQL UPDATE语句执行链路解析
数据库·mysql
南城花随雪。3 小时前
硬盘(HDD)与固态硬盘(SSD)详细解读
数据库