MongoDB聚合: $sort

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

语法

{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }

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

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

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

用法

需要注意:排序最多支持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"},
] )

使用$sortborough字段进行排序:

db.restaurants.aggregate(
   [
     { $sort : { borough : 1 } }
   ]
)

在这个例子中,多次排序结果的顺序就可能会有不同,因为borough字段包含ManhattanBrooklyn的重复值,文档按照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的值仍按字母顺序排序,但包含重复区值(即ManhattanBrooklyn)的文档的顺序却不一样。

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

db.restaurants.aggregate(
   [
     { $sort : { borough : 1, _id: 1 } }
   ]
)

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

举例

升序/降序排序

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

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" }表达式按相关性得分降序排序。在{ }文档中,将{ $meta: "textScore" }表达式设置为任意字段名称。查询系统将忽略字段名称。如:

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

你可能感兴趣的:(mongodb,mongodb,数据库)