文档菜单
文档首页
/ / /
Java 同步驱动程序
/

校对规则

本页内容

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

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

您可以在本指南的以下部分了解更多关于校对规则的信息

  • MongoDB中的校对规则

  • 如何指定校对规则

  • 校对选项

  • 校对代码示例

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

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

  • cote

  • coté

  • côte

  • côté

使用二进制排序规则时,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中应用校对的不同方式

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

您只能在创建集合时分配默认校对。然而,您可以在现有集合上的新索引中指定校对。有关更多信息,请参阅本指南的索引部分。

以下代码示例展示了在创建名为items:

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

的集合时指定“en_US”区域校对的方法

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", ... }
...
}

索引

  • 您可以在创建集合上的新索引时指定校对。索引存储了集合中文档的有序表示,因此您的操作不需要在内存中执行排序。要使用索引,您的操作必须满足以下标准

  • 操作使用与索引中指定的相同的校对。

操作被包含校对的索引所覆盖。

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);

的集合时指定“en_US”区域校对的方法

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()));

以下代码示例展示了如何创建一个对“name”字段进行升序排序的索引,并使用“en_US”区域校对

{ ...
"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索引类型支持排序规则,但以下类型仅支持二进制比较

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

排序规则选项
描述
区域设置
必需。语言和变体的ICU区域代码。
locale() API 文档
反向
是否首先考虑字符串末尾的重音符号。
backwards() API 文档
大小写敏感
是否将大小写(大写或小写)视为不同的值。
caseLevel() API 文档
备选
是否考虑空格和标点符号。
首字母大小写
是否考虑首字母的大小写。
最大变量
是否忽略空白字符或空白字符和标点符号。此设置仅在替代设置为“shifted”时有效。
强度
ICU比较级别。默认值为"三级"。有关每个级别的更多信息,请参阅ICU比较级别
规范化
是否根据需要对文本进行Unicode规范化。有关Unicode规范化的更多信息,请参阅Unicode规范化形式
normalization() API 文档
数值排序
是否按数值排序而不是按排序规则排序。

您可以使用 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操作。对于每个示例,假设您从以下文档集合开始

{ "_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"变体中,带重音符号的字符在升序排序中排在没有重音符号的相同字符之前。

以下示例演示了如何在从集合检索排序结果时应用排序。要执行此操作,请在示例集合上调用 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" 排序规则。

  • 添加一个新字段 "verified",其值为 "true"。

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

注意

以下代码示例使用从 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());
}

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

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

有关本节中提到的方法和类的更多信息,请参阅以下API文档

本节演示了如何在删除查询的第一个匹配项的操作中指定排序规则。要为此操作指定排序规则,实例化一个 FindOneAndDeleteOptions 对象,在它上面设置一个数值排序规则,并将其作为参数传递给您的 findOneAndDelete() 方法调用。

此示例在包含以下文档的集合上调用 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文档

返回

事务