对结果进行排序
Overview
在本指南中,您可以了解如何使用排序操作对 MongoDB Kotlin 驱动程序的读取操作结果进行排序。
排序操作按指定的排序条件对查询返回的文档进行排序。 排序条件是您传递给 MongoDB 的规则,描述您希望如何对数据进行排序。 排序条件的一些示例如下:
最小数字到最大数字
一天中的最早时间到一天中的最晚时间
按名字字母顺序排列
您应阅读本指南,了解如何执行以下操作:
执行升序排序和降序排序
组合排序条件
本指南中的示例使用包含以下文档的样本集合:
{ "_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( 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)
文本搜索(Text Search)
Atlas Searchstring您可以通过集合的文本索引指定的每个结果字段的 值与 的匹配程度来指定 文本Atlas Searchstring 结果的顺序。文本Atlas Search会分配一个数字文本分数,以指示每个结果与Atlas Search string的匹配程度。 使用Sorts.metaTextScore()
静态工厂方法构建排序条件,按文本分数进行排序。
在以下代码示例中,我们将向您展示如何使用Sorts.metaTextScore()
方法对Atlas Search 样本集合 上的文本 的结果进行排序。该代码示例使用Filters 、 Indexes和Projections构建器。
该代码示例执行以下操作:
在
description
字段上为样本集合创建文本索引。 如果调用createIndex()
时指定集合中已存在的索引,则该操作不会创建新索引。对短语
"vanilla"
运行文本搜索。将文本分数作为
score
字段投影到查询结果中。按文本得分对结果进行排序(最匹配的排在前面)。
数据使用以下 Kotlin 数据类进行建模:
data class OrderScore( 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聚合管道操作符的更多信息,请参阅服务器手册文档。