排序规则(Collations)
排序规则在 MongoDB 3.4 及更高版本中可用。
Overview
本指南将向您介绍如何使用排序规则(一组排序规则),针对特定语言和语言区域(具有共同语言习惯的社区或地区)使用字符串排序来运行操作。
MongoDB默认使用二进制排序规则对字符串进行排序。此排序规则方法使用 ASCII 标准 字符值对字符串进行比较和排序。语言和区域设置具有与 ASCII 标准不同的特定字符排序约定。
例如,在加拿大法语中,当其他字符相同时,最右边的重音字符决定字符串的顺序。考虑以下法语单词:cote、coté、côte 和 côté。
MongoDB 使用默认二进制排序规则并按以下顺序对它们进行排序:
cote coté côte côté
MongoDB 使用加拿大法语排序规则按以下顺序排序:
cote côte coté côté
使用
您可以在创建新集合或新索引时指定排序规则。 您还可以为 CRUD操作和聚合指定排序规则。
当您使用排序规则创建新集合时,您可以为支持在该集合上调用的排序规则的任何操作定义默认排序规则。您可以通过指定其他排序规则来覆盖操作的排序规则。
注意
目前,您无法对现有集合创建排序规则。要对现有集合使用排序规则,请使用该排序规则创建索引,并在对其进行操作时指定相同的排序规则。
创建带有排序规则的索引时,需要为使用该索引的操作指定排序顺序。如需在索引中使用排序规则,必须提供操作的匹配排序规则,并且操作必须使用索引。虽然大多数索引类型都支持排序规则,但以下类型只支持二进制比较:
排序规则参数
排序规则对象包含以下参数
collation: { locale: <string>, caseLevel: <bool>, caseFirst: <string>, strength: <int>, numericOrdering: <bool>, alternate: <string>, maxVariable: <string>, backwards: <bool> }
您必须在排序规则中指定 locale
字段;所有其他字段均为可选字段。 有关支持的区域设置以及locale
字段默认值的完整列表,请参阅支持的语言和区域设置。 有关每个字段的说明,请参阅MongoDB 手册中的排序规则文档条目。
排序规则示例
在集合上设置默认排序规则
以下示例中,我们创建了名为 souvenirs
的新集合,为其指定了 "fr_CA"
区域设置的默认排序规则。排序规则适用于在该集合上执行的所有支持排序规则的操作。
db.createCollection("souvenirs", { collation: { locale: "fr_CA" }, });
任何支持排序规则的操作都会自动应用集合上定义的排序规则。以下查询会搜索 souvenirs
集合,然后应用 "fr_CA"
区域设置排序规则:
myColl.find({type: "photograph"});
您可以在支持排序规则的操作中指定不同的排序规则作为参数。以下查询指定了 "is"
冰岛区域设置和 caseFirst
可选参数,参数值为 "upper"
:
myColl.find({type: "photograph"}, { collation: { locale: "is", caseFirst: "upper" } } );
为索引指定排序规则
以下示例中,我们在集合的 title
字段上创建新索引,该索引的排序规则设置为 "en_US"
区域设置。
myColl.createIndex( { 'title' : 1 }, { 'collation' : { 'locale' : 'en_US' } });
以下查询使用我们创建的索引:
myColl.find({"year": 1980}, {"collation" : {"locale" : "en_US" }}) .sort({"title": -1});
以下查询不使用我们创建的索引。第一个查询不包含排序规则,第二个查询包含的排序强度值与索引上的排序规则不同。
myColl.find({"year": 1980}, {"collation" : {"locale" : "en_US", "strength": 2 }}) .sort({"title": -1});
myColl.find({"year": 1980}) .sort({"title": -1});
排序规则查询示例
从集合中读取、更新和删除文档的操作可以使用排序规则。 本节包括其中的一些选择示例。 有关支持排序规则的操作的完整列表,请参阅 MongoDB 手册。
find() 和 sort() 示例
以下示例对使用默认二进制排序规则的集合调用 find()
和 sort()
。我们通过将 locale
参数的值设置为 "de"
来使用德语排序规则。
myColl.find({ city: "New York" }, { collation: { locale: "de" } }) .sort({ name: 1 });
findOneAndUpdate() 示例
以下示例对使用默认二进制排序规则的集合调用 findOneAndUpdate()
操作。该集合包含以下文档:
{ "_id" : 1, "first_name" : "Hans" } { "_id" : 2, "first_name" : "Gunter" } { "_id" : 3, "first_name" : "Günter" } { "_id" : 4, "first_name" : "Jürgen" }
考虑对该集合进行以下 findOneAndUpdate()
操作,该操作未指定排序规则:
myColl.findOneAndUpdate( { first_name : { $lt: "Gunter" } }, { $set: { verified: true } } );
由于 "Gunter" 是使用二进制排序规则时的第一个排序结果,因此没有任何文档在词法上排在查询文档的 $lt
比较操作符之前并与之匹配。因此该操作不会更新任何文档。
指定排序规则时,考虑同样的操作,并将语言区域设置为 de@collation=phonebook
。该语言区域指定了 collation=phonebook
选项,其中包含对专有名词进行优先排序的规则,通过首字母大写来标识。de@collation=phonebook
语言区域和选项可将带变音符号的字符排序在不带变音符号的相同字符之前。
myColl.findOneAndUpdate( { first_name: { $lt: "Gunter" } }, { $set: { verified: true } }, { collation: { locale: "de@collation=phonebook" } }, );
由于使用 findOneAndUpdate()
中指定的 de@collation=phonebook
排序规则,“Günter”在词法上位于“Gunter”之前,因此该操作返回以下更新文档:
{ lastErrorObject: { updatedExisting: true, n: 1 }, value: { _id: 3, first_name: 'Günter' }, ok: 1 }
findOneAndDelete() 示例
以下示例对使用默认二进制排序规则并包含以下文档的集合调用 findOneAndDelete()
操作:
{ "_id" : 1, "a" : "16" } { "_id" : 2, "a" : "84" } { "_id" : 3, "a" : "179" }
在本例中,我们将 numericOrdering
排序规则参数设置为 true
,以便根据数字字符串的数字顺序而不是词法顺序排序。
myColl.findOneAndDelete( { a: { $gt: "100" } }, { collation: { locale: "en", numericOrdering: true } }, );
运行上述操作后,集合将包含以下文档:
{ "_id" : 1, "a" : "16" } { "_id" : 2, "a" : "84" }
如果在没有排序规则的情况下对包含三个文档的原始集合执行相同的操作,则会根据字符串的词法值("16"
、"84"
和 "179"
)匹配文档,然后删除找到的第一个与查询条件匹配的文档。
await myColl.findOneAndDelete({ a: { $gt: "100" } });
由于所有文档的 a
字段中都包含符合标准的词法值(大于词法值 "100"
),因此该操作会删除第一个结果。运行上述操作后,集合中将包含以下文档:
{ "_id" : 2, "a" : "84" } { "_id" : 3, "a" : "179" }
聚合示例
要在聚合操作中使用排序规则,请在管道阶段数组之后传递选项字段中的排序规则文档。
以下示例显示了在使用默认二进制排序规则的集合上的聚合管道。聚合对 first_name
字段分组,计算每组结果的总数,然后按照德语电话簿("de@collation=phonebook"
语言区域)顺序对结果排序。
注意
您只能对聚合指定一个排序规则。
myColl.aggregate( [ { $group: { "_id": "$first_name", "nameCount": { "$sum": 1 } } }, { $sort: { "_id": 1 } }, ], { collation: { locale: "de@collation=phonebook" } }, );