Docs 菜单
Docs 主页
/ / /
Kotlin 协程
/ / /

对结果进行排序

在此页面上

  • Overview
  • 排序方法
  • 排序方向
  • 升序
  • 降序
  • 处理秩
  • 组合排序标准
  • 文本搜索(Text Search)

在本指南中,您可以了解如何使用排序操作对 MongoDB Kotlin 驱动程序的读取操作结果进行排序。

排序操作按指定的排序条件对查询返回的文档进行排序。 排序条件是您传递给 MongoDB 的规则,描述您希望如何对数据进行排序。 排序条件的一些示例如下:

  • 最小数字到最大数字

  • 一天中的最早时间到一天中的最晚时间

  • 按名字字母顺序排列

您应阅读本指南,了解如何执行以下操作:

  • 执行升序排序和降序排序

  • 组合排序条件

  • 根据 文本的文本分数进行排序Atlas Search

本指南中的示例使用包含以下文档的样本集合:

{ "_id": 1, "date": "2022-01-03", "orderTotal": 17.86, "description": "1/2 lb cream cheese and 1 dozen bagels" },
{ "_id": 2, "date": "2022-01-11", "orderTotal": 83.87, "description": "two medium vanilla birthday cakes" },
{ "_id": 3, "date": "2022-01-11", "orderTotal": 19.49, "description": "1 dozen vanilla cupcakes" },
{ "_id": 4, "date": "2022-01-15", "orderTotal": 43.62, "description": "2 chicken lunches and a diet coke" },
{ "_id": 5, "date": "2022-01-23", "orderTotal": 60.31, "description": "one large vanilla and chocolate cake" },
{ "_id": 6, "date": "2022-01-23", "orderTotal": 10.99, "description": "1 bagel, 1 orange juice, 1 muffin" }

此数据使用以下 Kotlin 数据类进行建模:

data class Order(
@BsonId val id: Int,
val date: String,
val orderTotal: Double,
val description: String,
)

您可以对查询检索的结果进行排序,也可以在聚合管道内对结果进行排序。

要对查询结果进行排序,请使用 FindFlow实例的 sort() 方法。 要对聚合管道中的结果进行排序,请使用 Aggregates.sort() 静态工厂方法。 这两个方法都接收实现Bson 接口的对象作为参数。 有关更多信息,请参阅BSON接口的API文档。

您可以使用FindFlow实例的sort()方法,如下所示:

val resultsFlow = collection.find().sort(Sorts.ascending(Order::orderTotal.name))

您可以在聚合管道中使用Aggregates.sort()方法,按orderTotal字段的最小值到最大值对样本集合中的文档进行排序,如下所示:

val resultsFlow = collection.aggregate(listOf(
Aggregates.sort(Sorts.ascending(Order::orderTotal.name))
))
resultsFlow.collect { println(it) }
Order(id=6, date=2022-01-23, orderTotal=10.99, description=1 bagel, 1 orange juice, 1 muffin)
Order(id=1, date=2022-01-03, orderTotal=17.86, description=1/2 lb cream cheese and 1 dozen bagels)
Order(id=3, date=2022-01-11, orderTotal=19.49, description=1 dozen vanilla cupcakes)
Order(id=4, date=2022-01-15, orderTotal=43.62, description=2 chicken lunches and a diet coke)
Order(id=5, date=2022-01-23, orderTotal=60.31, description=one large vanilla and chocolate cake)
Order(id=2, date=2022-01-11, orderTotal=83.87, description=two medium vanilla birthday cakes)

在前面的代码片段中,我们使用Sorts构建器类指定排序条件。 虽然可以使用任何实现Bson接口的类指定排序条件,但我们建议您通过Sorts构建器指定排序条件。 有关Sorts构建器类的更多信息,请参阅排序构建器指南。

有关此部分中的类和接口的更多信息,请参阅以下 API 文档:

排序方向可以是升序,也可以是降序。 升序排序可将结果从小到大进行排序。 降序排序将结果按从大到小的顺序排列。

以下是按升序排序的数据的一些示例:

  • 数字:1、2、3、43、43、55、120

  • 日期:1990-03-10、1995-01-01、2005-10-30、2005-12-21

  • 单词 (ASCII):Banana,Dill,carrot,cucumber,hummus

以下是按降序排序的数据的一些示例:

  • 数字:100、30、12、12、9、3、1

  • 日期:2020 年 1 月 1 日、1998 年 12 月 11 日、1998 年 12 月 10 日、1975 年 7 月 22 日

  • 单词(反向 ASCII):pear、graves、apple、Cheese

以下各小节介绍如何指定这些排序条件。

要指定升序排序,请使用Sorts.ascending()静态工厂方法。 向Sorts.ascending()方法传递需要按升序排序的字段的名称。

您可以将Sorts.ascending()方法的输出传递给sort()方法,以指定对字段进行升序排序,如下所示:

collection.find().sort(Sorts.ascending("<field name>"))

前面的sort()方法返回一个FindIterable对象,该对象可以迭代集合中的文档,并按指定字段名称从小到大排序。

在以下代码示例中,我们使用ascending()方法按orderTotal字段对样本集合进行排序:

val resultsFlow = collection.find()
.sort(Sorts.ascending(Order::orderTotal.name))
resultsFlow.collect { println(it) }
Order(id=6, date=2022-01-23, orderTotal=10.99, description=1 bagel, 1 orange juice, 1 muffin)
Order(id=1, date=2022-01-03, orderTotal=17.86, description=1/2 lb cream cheese and 1 dozen bagels)
Order(id=3, date=2022-01-11, orderTotal=19.49, description=1 dozen vanilla cupcakes)
Order(id=4, date=2022-01-15, orderTotal=43.62, description=2 chicken lunches and a diet coke)
Order(id=5, date=2022-01-23, orderTotal=60.31, description=one large vanilla and chocolate cake)
Order(id=2, date=2022-01-11, orderTotal=83.87, description=two medium vanilla birthday cakes)

要指定降序排序,请使用Sorts.descending()静态工厂方法。 向Sorts.descending()方法传递需要按降序排序的字段的名称。

以下代码片段演示如何指定对orderTotal字段进行降序排序,并按降序返回样本集合中的文档:

val resultsFlow = collection.find()
.sort(Sorts.descending(Order::orderTotal.name))
resultsFlow.collect { println(it) }
Order(id=2, date=2022-01-11, orderTotal=83.87, description=two medium vanilla birthday cakes)
Order(id=5, date=2022-01-23, orderTotal=60.31, description=one large vanilla and chocolate cake)
Order(id=4, date=2022-01-15, orderTotal=43.62, description=2 chicken lunches and a diet coke)
Order(id=3, date=2022-01-11, orderTotal=19.49, description=1 dozen vanilla cupcakes)
Order(id=1, date=2022-01-03, orderTotal=17.86, description=1/2 lb cream cheese and 1 dozen bagels)
Order(id=6, date=2022-01-23, orderTotal=10.99, description=1 bagel, 1 orange juice, 1 muffin)

当两个或多个文档在用于对结果进行排序的字段中具有相同的值时,就会出现“并列”情况。 MongoDB 不保证出现并列时的排序顺序。 例如,假设我们使用以下代码对样本集合进行排序时遇到平局:

collection.find().sort(Sorts.ascending(Order::date.name))

由于与查询匹配的多个文档的date字段包含相同的值,因此返回的文档顺序可能不一致。

如果需要保证具有相同值字段的文档的特定顺序,则可以指定其他字段,以在出现事件作为排序依据。

我们可以指定对date字段进行升序排序,然后对orderTotal字段进行升序排序,从而按以下顺序返回样本集合中的文档:

collection.find().sort(Sorts.ascending(Order::date.name, Order::orderTotal.name))
Order(id=1, date=2022-01-03, orderTotal=17.86, description=1/2 lb cream cheese and 1 dozen bagels)
Order(id=3, date=2022-01-11, orderTotal=19.49, description=1 dozen vanilla cupcakes)
Order(id=2, date=2022-01-11, orderTotal=83.87, description=two medium vanilla birthday cakes)
Order(id=4, date=2022-01-15, orderTotal=43.62, description=2 chicken lunches and a diet coke)
Order(id=6, date=2022-01-23, orderTotal=10.99, description=1 bagel, 1 orange juice, 1 muffin)
Order(id=5, date=2022-01-23, orderTotal=60.31, description=one large vanilla and chocolate cake)

要组合排序条件,请使用Sorts.orderBy()静态工厂方法。 此方法可构造一个对象,其中包含排序条件的有序列表。 执行排序时,如果前一个排序条件的结果为并列,则排序将使用列表中的下一个排序条件来确定顺序。

在以下代码片段中,我们使用orderBy()方法对数据进行排序,具体方法是对date字段执行降序排序;如果出现平局,则对orderTotal字段执行升序排序。 使用这些排序条件,代码按以下顺序返回样本集合中的文档:

val orderBySort = Sorts.orderBy(
Sorts.descending(Order::date.name), Sorts.ascending(Order::orderTotal.name)
)
val results = collection.find().sort(orderBySort)
results.collect {println(it) }
Order(id=6, date=2022-01-23, orderTotal=10.99, description=1 bagel, 1 orange juice, 1 muffin)
Order(id=5, date=2022-01-23, orderTotal=60.31, description=one large vanilla and chocolate cake)
Order(id=4, date=2022-01-15, orderTotal=43.62, description=2 chicken lunches and a diet coke)
Order(id=3, date=2022-01-11, orderTotal=19.49, description=1 dozen vanilla cupcakes)
Order(id=2, date=2022-01-11, orderTotal=83.87, description=two medium vanilla birthday cakes)
Order(id=1, date=2022-01-03, orderTotal=17.86, description=1/2 lb cream cheese and 1 dozen bagels)

Atlas Searchstring您可以通过集合的文本索引指定的每个结果字段的 值与 的匹配程度来指定 文本Atlas Searchstring 结果的顺序。文本Atlas Search会分配一个数字文本分数,以指示每个结果与Atlas Search string的匹配程度。 使用Sorts.metaTextScore()静态工厂方法构建排序条件,按文本分数进行排序。

重要

确保创建文本索引

您需要在集合上建立文本索引才能执行文本Atlas Search 。 有关如何创建文本索引的更多信息,请参阅服务器手册文档。

在以下代码示例中,我们将向您展示如何使用Sorts.metaTextScore() 方法对Atlas Search 样本集合 上的文本 的结果进行排序。该代码示例使用FiltersIndexesProjections构建器。

该代码示例执行以下操作:

  1. description字段上为样本集合创建文本索引。 如果调用createIndex()时指定集合中已存在的索引,则该操作不会创建新索引。

  2. 对短语"vanilla"运行文本搜索。

  3. 将文本分数作为score字段投影到查询结果中。

  4. 按文本得分对结果进行排序(最匹配的排在前面)。

数据使用以下 Kotlin 数据类进行建模:

data class OrderScore(
@BsonId val id: Int,
val description: String,
val score: Double
)
import com.mongodb.client.model.Sorts
import com.mongodb.client.model.Projections
import com.mongodb.client.model.Filters
import com.mongodb.client.model.Indexes
collection.createIndex(Indexes.text(Order::description.name))
val metaTextScoreSort = Sorts.orderBy(
Sorts.metaTextScore(OrderScore::score.name),
Sorts.descending("_id")
)
val metaTextScoreProj = Projections.metaTextScore(OrderScore::score.name)
val searchTerm = "vanilla"
val searchQuery = Filters.text(searchTerm)
val results = collection.find<OrderScore>(searchQuery)
.projection(metaTextScoreProj)
.sort(metaTextScoreSort)
results.collect { println(it) }
OrderScore(id=3, description=1 dozen vanilla cupcakes, score=0.625)
OrderScore(id=5, description=one large vanilla and chocolate cake, score=0.6)
OrderScore(id=2, description=two medium vanilla birthday cakes, score=0.6)

注意

或更高版本中的文本Atlas Search 行为MongoDB4.4

MongoDB 4.4 或更高版本的文本搜索结构已更改。 您不再需要将Projections.metaTextScore()投影到FindFlow实例中以对文本分数进行排序。 此外,在排序中使用的$meta文本分数聚合操作中指定的字段名称将被忽略。 这意味着您传递给Sorts.metaTextScore()的字段名称参数将被忽略。

有关本节中类的更多信息,请参阅以下 API 文档:

有关详细信息,请参阅 Sorts 类 API 文档。有关$text查询操作符和$meta聚合管道操作符的更多信息,请参阅服务器手册文档。

后退

打开变更流