Definition 定义

对所有输入的文档进行排序,并按排序后的顺序返回给 pipeline。

$sort stage 的原型形式如下:

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

$sort 接收一个文档,指定要排序的字段各自的排序顺序<sort order>可以有以下值之一:

Value Description
1 升序排序(ascending)
-1 降序排序(descending)
{ $meta: "textScore" } 按计算的 textScore 元数据降序排序。 有关示例,请参阅 Text Score Metadata Sort(文本分数元数据排序)

如果对多个字段进行排序,排序顺序将从左到右进行评估。例如,在上面的原型中,文档首先按 <field1> 进行排序。然后,具有相同 <field1> 值的文档进一步按 <field2> 进行排序。

Behavior 行为

Sort Consistency 一致性排序

MongoDB 不会以特定顺序将文档存储在集合中。 在对包含重复值的字段进行排序时,包含这些值的文档可以按任何顺序返回。

如果需要一致的排序顺序,请在排序中至少包含一个包含唯一值的字段。 保证这一点的最简单方法是在排序查询中包含 _id 字段。

考虑以下 restaurants collection:

  1. db.restaurants.insertMany( [
  2. { "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan"},
  3. { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens"},
  4. { "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn"},
  5. { "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan"},
  6. { "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn"},
  7. ] );

以下命令使用 $sort stage 对 borough 字段进行排序(升序):

  1. db.restaurants.aggregate( [
  2. {
  3. $sort: { borough: 1 }
  4. }
  5. ] )

在此示例中,排序顺序可能不一致,因为 borough 字段包含 ManhattanBrooklyn 的重复值。 文档是按 borough 的字母顺序返回,但对于 borough 具有重复值的那些文档的顺序在同一排序的多次执行中可能不同。 例如,以下是上述命令的两次不同执行的结果:

  1. { "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn" }
  2. { "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn" }
  3. { "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan" }
  4. { "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan" }
  5. { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens" }
  6. { "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn" }
  7. { "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn" }
  8. { "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan" }
  9. { "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan" }
  10. { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens" }

虽然 borough 的值仍按字母顺序(alphabetical order)排序,但包含 borough 重复值(即 ManhattanBrooklyn)的文档的顺序并不相同。

要实现一致的排序,请向排序添加一个仅包含唯一值的字段。 以下命令使用 $sort stage 对 borough 字段和 _id 字段进行排序:

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

由于 _id 字段始终保证包含唯一的值,因此返回的排序顺序在同一排序的多次执行中总是相同的。

Example 例子

Asceding/Descending Sort 升序/降序排序

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

  1. db.users.aggregate(
  2. [
  3. { $sort : { age : -1, posts: 1 } }
  4. ]
  5. )

该 operation 对 users collection 中的文档进行排序,按照 age 字段降序排列,然后按照 posts 字段中的值升序排列。

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

  • MinKey(internal type)
  • Null
  • Numbers(ints、longs、doubles、decimals)
  • Symbol,String
  • Object
  • Array
  • BinData
  • ObjectId
  • Boolean
  • Date
  • Timestamp
  • Regular Expression
  • MaxKey(interval type)

有关特定类型的比较/排序顺序的详细信息,请参阅 Comparison/Sort Order

Text Score Metadata Sort 文本分数元数据排序

对于包含 $text 搜索的 pipeline,您可以使用 { $meta: “textScore” } expression 按相关性分数降序排序。 在 { <sort-key> } 文档中,将 { $meta: “textScore” } expression 设置为任意字段名称。 查询系统会忽略字段名称。 例如:

  1. db.users.aggregate(
  2. [
  3. { $match: { $text: { $search: "operating" } } },
  4. { $sort: { score: { $meta: "textScore" }, posts: -1 } }
  5. ]
  6. )

此操作使用 $text operator 匹配文档,然后首先按 "textScore" metadata 降序排序,然后按 posts 字段降序排序。 排序文档中的 score 字段名称被查询系统忽略。 在此 pipeline 中,"textScore" metadata 不包含在 projection 中,也不作为匹配文档的一部分返回。 有关更多信息,请参阅 $meta

$sort Operator and Memory $sort 运算符和内存

$sort + $limit Memory Optimization $sort + $limit 内存优化

$sort$limit 之前并且没有修改文档数量的干预 stage 时,优化器可以将 $limit 合并到 $sort 中。 这允许 $sort operation 在进行时只维护前 n 个结果,其中 n 是指定的限制,并确保 MongoDB 只需要在内存中存储 n 个项目(items)。 当 allowDiskUsetrue 并且 n 项(items)超过 aggregation memory limit(聚合内存限制)时,此优化仍然适用。

优化可能会在不同版本(releases)之间发生变化。

$sort and Memory Restrictions $sort 和内存限制

$sort stage 对内存中的排序有 100 兆字节的 RAM 限制。 默认情况下,如果 stage 超过此限制, $sort 会产生错误。 要允许 pipeline 处理占用更多空间,请使用 allowDiskUse 选项启用 aggregation pipeline stage 以将数据写入临时文件。

TIP 参阅: Aggregation Pipeline Limits 聚合管道限制

$sort Operator and Performance $sort 运算符和性能

如果 $sort operator 用于 pipeline 的第一 stage 或仅在 $match stage之前使用,则它可以利用索引(index)。

当您在分片集群(sharded cluster)上使用 $sort 时,每个分片都会使用可用的索引对其结果文档进行排序。 然后 mongos 或其中一个分片执行流式合并排序。

TIP 参阅:

参考

https://docs.mongodb.com/manual/reference/operator/aggregation/sort