Docs 菜单

Docs 主页开发应用程序MongoDB 驱动程序java sync

排序规则(Collations)

在此页面上

  • 概述
  • MongoDB 中的排序规则
  • 如何指定排序规则
  • Collection
  • 索引
  • 操作
  • 不支持排序规则的索引类型
  • 排序规则选项
  • 排序规则示例
  • find() 和 sort() 示例
  • findOneAndUpdate() 示例
  • findOneAndDelete() 示例
  • 聚合示例

在本指南中,您可以了解如何在 MongoDB 中使用排序规则,按字符串值对查询或聚合操作结果进行排序。 排序规则是一组适用于特定语言和区域设置的字符排序和匹配规则。

您可以在本指南的以下部分了解有关排序规则的更多信息:

  • MongoDB 中的排序规则

  • 如何指定排序规则

  • 排序规则选项

  • 排序规则代码示例

MongoDB 默认使用 二进制排序 规则对字符串进行排序。二进制排序规则使用 ASCII 标准 用于比较和排序字符串的字符值。某些语言和区域设置具有与 ASCII 字符值不同的特定字符排序约定。

例如,在加拿大法语中,当前面的所有字符都相同时,最右边的重音字符(变音符号)决定字符串的顺序。 考虑以下加拿大法语单词:

  • cote

  • 科特

  • 山坡

  • 山坡

使用二进制排序规则时,MongoDB 按以下顺序对它们进行排序:

cote
coté
côte
côté

当使用加拿大法语排序规则时,MongoDB 按不同的顺序对其进行排序,如下所示:

cote
côte
coté
côté

MongoDB 支持大多数CRUD 操作和聚合的排序规则。有关支持的操作的完整列表,请参阅《 支持排序规则的操作》服务器手册页面。

您可以使用以下字符串格式指定区域设置代码和可选变体:

"<locale code>@collation=<variant code>"

以下示例指定了 "de" 区域设置代码和 "phonebook" 变体代码:

"de@collation=phonebook"

如果不需要指定变体,请省略区域设置代码之后的所有内容,如下所示:

"de"

有关支持的区域设置的完整列表,请参阅有关支持的语言和区域设置的服务器手册页面。

以下部分向您展示在 MongoDB 中应用排序规则的不同方法:

您可以在创建collection时设置默认排序规则。使用指定排序规则创建集合时,扫描该集合的所有受支持操作都会应用该排序规则。

只有在创建集合时,才能为该集合指定默认排序规则。但是,您可以在现有集合的新索引中指定排序规则。有关更多信息,请参阅本指南的索引部分。

以下代码片段展示了在创建名为 items的新collection时,如何指定“en_US”区域设置排序规则:

database.createCollection(
"items",
new CreateCollectionOptions().collation(
Collation.builder().locale("en_US").build()));

要检查是否成功创建排序规则,请检索该collection上的索引列表,如下所示:

MongoCollection<Document> collection = database.getCollection("items");
List<Document> indexes = new ArrayList<>();
collection.listIndexes().into(indexes);
// Prints the collection's indexes and any default collations
indexes.forEach(idx -> System.out.println(idx.toJson()));

代码的输出应包含以下内容:

{ ...
"collation": { "locale": "en_US", ... }
...
}

在collection上创建新索引时,可以指定排序规则。索引会将文档的有序表示形式存储在collection中,因此您的操作无需在内存中执行排序。要使用索引,您的操作必须满足以下条件:

  • 该操作使用与索引中指定的排序规则相同的排序规则。

  • 该操作由包含排序规则的索引涵盖。

以下代码片段展示了如何使用“en_US”区域设置排序规则在“名称”字段上按升序创建索引:

MongoCollection<Document> collection = database.getCollection("items");
IndexOptions idxOptions = new IndexOptions();
// Defines options that set a collation locale
idxOptions.collation(Collation.builder().locale("en_US").build());
// Creates an index on the "name" field with the collation and ascending sort order
collection.createIndex(Indexes.ascending("name"), idxOptions);

要检查是否成功创建排序规则,请检索该collection上的索引列表,如下所示:

MongoCollection<Document> collection = database.getCollection("items");
List<Document> indexes = new ArrayList<>();
collection.listIndexes().into(indexes);
// Prints the collection's indexes and any default collations
indexes.forEach(idx -> System.out.println(idx.toJson()));

上述代码的输出应包含以下内容:

{ ...
"collation": { "locale": "en_US", ... }
...
}

以下代码片段显示了一个示例操作,该操作指定相同的排序规则,并由我们在前面的代码片段中创建的索引覆盖:

FindIterable<Document> cursor = collection.find()
.collation(Collation.builder().locale("en_US").build())
.sort(Sorts.ascending("name"));

您可以通过将新排序规则作为参数传递给支持的操作之一来覆盖集合上的默认排序规则。但是,由于该操作不使用索引,因此该操作的性能可能不如使用索引的操作。有关索引未涵盖的排序操作缺点的更多信息,请参阅有关使用索引对查询结果进行排序的服务器手册页面。

以下代码片段显示了具有以下特征的示例查询操作:

  • 引用的集合包含默认排序规则“en_US”,其类似于集合部分中指定的排序规则。

  • 查询指定了冰岛语 ("is") 排序规则,但集合的默认排序规则索引未涵盖该排序规则。

  • 由于索引未涵盖指定的排序规则,因此排序操作在内存中执行。

FindIterable<Document> cursor = collection.find()
.collation(Collation.builder().locale("is").build())
.sort(Sorts.ascending("name"));

虽然大多数 MongoDB 索引类型都支持排序规则,但以下类型仅支持二进制比较:

本节介绍各种排序规则选项以及如何指定它们以进一步完善排序和匹配行为。

排序规则选项
说明
locale
必需。 语言和变体的 ICU 区域设置代码。
locale() API 文档
backwards
是否首先从字符串末尾考虑变音符号。
backwards() API 文档
区分大小写
是否将大小写(大写或小写)视为不同的值。
caseLevel() API 文档
替代方案
是否考虑空格和标点符号。
caseFirst
首先考虑大写还是小写。
最大变量
是忽略空格还是同时忽略空格和标点符号。 此设置仅在备用设置为“shift”时才有效。
strength
ICU 比较级别。默认值为“tertiary”。有关每个级别的更多信息,请参阅 ICU 比较级别
normalization
是否按需对文本进行 unicode 规范化。有关 unicode 规范化的更多信息,请参阅 Unicode 规范化形式
normalization() API 文档
numericOrdering
是否根据数值而不是排序规则对数字进行排序。

您可以使用Collation.Builder类为上述排序规则选项指定值。 您可以调用build()方法来构造Collation对象,如以下代码片段所示:

Collation.builder()
.caseLevel(true)
.collationAlternate(CollationAlternate.SHIFTED)
.collationCaseFirst(CollationCaseFirst.UPPER)
.collationMaxVariable(CollationMaxVariable.SPACE)
.collationStrength(CollationStrength.SECONDARY)
.locale("en_US")
.normalization(false)
.numericOrdering(true)
.build();

有关相应方法和它们采用的参数的更多信息,请参阅 Collation.Builder 的 API 文档。

本节包含的示例演示如何使用一系列支持排序规则的 MongoDB 操作。 对于每个示例,假设您从以下collection of 文档开始:

{ "_id" : 1, "first_name" : "Klara" }
{ "_id" : 2, "first_name" : "Gunter" }
{ "_id" : 3, "first_name" : "Günter" }
{ "_id" : 4, "first_name" : "Jürgen" }
{ "_id" : 5, "first_name" : "Hannah" }

在以下示例中,我们指定 "de@collation=phonebook" 区域设置和变体排序规则。 排序规则的“de”部分指定德语区域设置,“collation=phonebook”部分指定变体。 “de”区域设置排序规则包含对专有名词进行优先排序的规则,通过首字母大写进行标识。 在“collation=phonebook”变体中,按升序排序,带变音符号的字符排在不带变音符号的相同字符之前。

以下示例演示了如何在从collection中检索排序结果时应用排序规则。要执行此操作,请对示例collection调用find() ,并链接collation()sort()方法以指定接收结果的顺序。

注意

为方便起见,以下代码示例使用了来自import com.mongodb.client.model包的导入。

List<Document> results = new ArrayList<>();
// Retrieves all documents and applies a "de@collation-phonebook" collation and ascending sort to the results
collection.find()
.collation(Collation.builder().locale("de@collation=phonebook").build())
.sort(Sorts.ascending("first_name")).into(results);
// Prints the JSON representation of the results
if (results != null) {
results.forEach(doc -> System.out.println(doc.toJson()));
}

当我们对示例集合执行此操作时,输出应如下所示:

{"_id": 3, "first_name": "Günter"}
{"_id": 2, "first_name": "Gunter"}
{"_id": 5, "first_name": "Hannah"}
{"_id": 4, "first_name": "Jürgen"}
{"_id": 1, "first_name": "Klara"}

有关本节中提到的方法和类的详情,请参阅以下 API 文档:

本部分演示如何在更新查询中第一个匹配项的操作中指定排序规则。要指定此操作的排序规则,请实例化一个 FindOneAndUpdateOptions 对象,为其设置排序规则,然后将其作为参数传递给对 findOneAndUpdate() 方法的调用。

在此示例中,我们将演示以下内容:

  • 检索示例集合中按升序排列位于 "Gunter" 之前的第一个文档。

  • 设置操作选项,包括“de@collation=phonebook”排序规则。

  • 添加值为“true”的新字段“verified”。

  • 检索并打印更新后的文档。

注意

为方便起见,以下代码示例使用了来自import com.mongodb.client.model包的导入。

Document result = collection.findOneAndUpdate(
Filters.gt("first_name", "Gunter"),
Updates.set("verified", true),
new FindOneAndUpdateOptions()
.collation(Collation.builder().locale("de@collation=phonebook").build())
.sort(Sorts.ascending("first_name"))
.returnDocument(ReturnDocument.AFTER));
// Prints the JSON representation of the updated document if an update occurred
if (result != null) {
System.out.println("Updated document: " + result.toJson());
}

由于使用 de@collation=phonebook 排序规则按升序排列,“Günter”在词法上位于“Gunter”之前,因此前面的操作返回以下更新文档:

{
lastErrorObject: { updatedExisting: true, n: 1 },
value: { _id: 3, first_name: 'Günter' },
ok: 1
}

有关本节中提到的方法和类的详情,请参阅以下 API 文档:

本部分演示如何在删除查询中第一个匹配项的操作中指定排序规则中字符串的数字顺序。 要为此操作指定排序规则,请实例化一个FindOneAndDeleteOptions对象,为其设置数字排序规则,并将其作为参数传递给findOneAndDelete()方法。

此示例对包含以下文档的collection调用findOneAndDelete()操作:

{ "_id" : 1, "a" : "16 apples" }
{ "_id" : 2, "a" : "84 oranges" }
{ "_id" : 3, "a" : "179 bananas" }

在排序规则中,我们将locale选项设置为“en”,将numericOrdering选项设置为“true”,以便根据字符串的数字顺序对字符串进行排序。

注意

为方便起见,以下代码示例使用了来自import com.mongodb.client.model包的导入。

Document result = collection.findOneAndDelete(
Filters.gt("a", "100"),
new FindOneAndDeleteOptions()
.collation(
Collation.builder()
.locale("en")
.numericOrdering(true)
.build())
.sort(Sorts.ascending("a")));
// Prints the JSON representation of the deleted document
if (result != null) {
System.out.println("Deleted document: " + result.toJson());
}

运行上述操作后,输出应如下所示:

Deleted document: {"_id": 3, "a": "179 bananas"}

字符串“179”的数值大于数字 100,因此前面的文档是唯一匹配项。

如果我们对包含三个文档的原始集合执行相同的操作而不使用数字排序规则,则过滤器会匹配所有文档,因为按照二进制排序规则排序时,“100”在“16”、“84”、“179”之前。

有关本节中提到的方法和类的详情,请参阅以下 API 文档:

本节演示如何在聚合操作中指定排序规则。 在聚合操作中,您可以指定一系列聚合阶段,这些阶段统称为聚合管道。 要执行聚合,请对MongoCollection对象调用aggregate()方法。

要为聚合操作指定排序规则,请对聚合操作返回的AggregateIterable调用collation()方法。 确保在聚合管道中指定要应用排序规则的排序聚合阶段。

以下示例展示了如何在示例集合上构建聚合管道,并通过指定以下内容来应用排序规则:

  • 群组聚合阶段,使用Aggregates.group() first_name辅助程序通过文档的字段识别每个文档,并将该值用作结果的_id

  • 群组聚合阶段的累加器,用于对first_name字段中匹配值的实例数求和。

  • 对先前聚合阶段的输出文档的_id字段应用升序排序。

  • 构造排序规则对象,指定德语区域设置以及忽略重音和变音符号的排序规则强度。

Bson groupStage = Aggregates.group("$first_name", Accumulators.sum("nameCount", 1));
Bson sortStage = Aggregates.sort(Sorts.ascending("_id"));
AggregateIterable<Document> results = collection
// Runs the aggregation pipeline that includes tallying "first_name" frequencies
.aggregate(Arrays.asList(groupStage, sortStage))
// Applies a collation to sort documents alphabetically by using the German locale, ignoring accents
.collation(Collation.builder().locale("de").collationStrength(CollationStrength.PRIMARY).build());
// Prints the JSON representation of the results
if (results != null) {
results.forEach(doc -> System.out.println(doc.toJson()));
}

上述代码输出以下文档:

{"_id": "Gunter", "nameCount": 2}
{"_id": "Hannah", "nameCount": 1}
{"_id": "Jürgen", "nameCount": 1}
{"_id": "Klara", "nameCount": 1}

有关本节中提到的方法和类的详情,请参阅以下 API 文档:

← 索引