排序规则
概述
新增在版本3.4.
排序规则是用于比较字符串的规则集合,通常用于特定的自然语言。
例如,在加拿大法语中,给定单词的最后一个重音符号决定了排序顺序。
考虑以下法语单词
cote < coté < côte < côté
使用加拿大法语排序规则进行的排序顺序将得到以下结果
cote < côte < coté < côté
如果未指定排序规则,MongoDB 使用字符串的简单二进制比较。因此,单词的排序顺序将是
cote < coté < côte < côté
用法
您可以在创建集合和索引时指定默认的排序规则,或者指定 CRUD 操作和聚合的排序规则。对于支持排序规则的操作,MongoDB 使用集合的默认排序规则,除非操作指定了不同的排序规则。
排序规则参数
'collation' => { 'locale' => <string>, 'caseLevel' => <bool>, 'caseFirst' => <string>, 'strength' => <int>, 'numericOrdering' => <bool>, 'alternate' => <string>, 'maxVariable' => <string>, 'normalization' => <bool>, 'backwards' => <bool> }
唯一必需的参数是locale
,服务器将其解析为ICU 格式区域设置 ID例如,将 locale
设置为 en_US
以表示美国英语或 fr_CA
以表示加拿大法语。
有关可用参数的完整描述,请参阅 MongoDB 手册条目。
将默认排序规则分配给集合
以下示例在 test
数据库上创建一个名为 contacts
的新集合,并分配一个具有 fr_CA
区域设置的默认排序规则。在创建集合时指定排序规则确保所有针对 contacts
集合运行涉及查询的操作都使用 fr_CA
排序规则,除非查询指定了另一个排序规则。新集合上的任何索引也会继承默认排序规则,除非创建命令指定了另一个排序规则。
client = Mongo::Client.new([ "127.0.0.1:27017" ], :database => "test") client[:contacts, { "collation" => { "locale" => "fr_CA" } } ].create
将排序规则分配给索引
要指定索引的排序规则,请在创建索引时使用 collation
选项。
以下示例在address_book
集合的name
字段上创建了一个索引,启用了unique
参数,并使用默认排序规则,将locale
设置为en_US
。
client = Mongo::Client.new([ "127.0.0.1:27017" ], :database => "test") client[:address_book].indexes.create_one( { "first_name" => 1 }, "unique" => true, "collation" => { "locale" => "en_US" } )
要使用此索引,请确保您的查询也指定了相同的排序规则。以下查询使用了上述索引
client[:address_book].find({"first_name" : "Adam" }, "collation" => { "locale" => "en_US" })
以下查询不使用索引。第一个查询没有指定排序规则,第二个查询使用的排序规则与索引上的排序规则相比具有不同的strength
值。
client[:address_book].find({"first_name" : "Adam" }) client[:address_book].find({"first_name" : "Adam" }, "collation" => { "locale" => "en_US", "strength" => 2 })
支持排序规则的操作
所有读取、更新和删除方法都支持排序规则。以下是一些示例。
find()
和sort()
单个查询可以指定用于匹配和排序结果的排序规则。以下查询和排序操作使用德语排序规则,将locale
参数设置为de
。
client = Mongo::Client.new([ "127.0.0.1:27017" ], :database => "test") docs = client[:contacts].find({ "city" => "New York" }, { "collation" => { "locale" => "de" } }).sort( "name" => 1 )
find_one_and_update()
名为 names
的集合包含以下文档
{ "_id" : 1, "first_name" : "Hans" } { "_id" : 2, "first_name" : "Gunter" } { "_id" : 3, "first_name" : "Günter" } { "_id" : 4, "first_name" : "Jürgen" }
在集合上执行的以下 find_one_and_update
操作未指定排序。
client = Mongo::Client.new([ "127.0.0.1:27017" ], :database => "test") doc = client[:names].find_one_and_update( {"first_name" => { "$lt" => "Gunter" }}, { "$set" => { "verified" => true } })
因为 Gunter
在集合中按字典序排在最前面,上述操作没有返回结果,也没有更新任何文档。
考虑相同的 find_one_and_update
操作,但指定了排序。区域设置为 de@collation=phonebook
。
注意
一些区域提供了 collation=phonebook
选项,用于与那些将专有名词与其他单词按不同顺序排序的语言一起使用。根据 de@collation=phonebook
排序,带变音符号的字符排在相同不带变音符号的字符之前。
client = Mongo::Client.new([ "127.0.0.1:27017" ], :database => "test") doc = client[:names].find_one_and_update( { "first_name" => { "$lt" => "Gunter" } }, { "$set" => { "verified" => true } }, { "collation" => { "locale" => "de@collation=phonebook" }, :return_document => :after } )
操作返回以下更新后的文档
{ "_id" => 3, "first_name" => "Günter", "verified" => true }
find_one_and_delete()
将 numericOrdering
排序参数设置为 true
以按数值比较数值字符串。
名为 numbers
的集合包含以下文档
{ "_id" : 1, "a" : "16" } { "_id" : 2, "a" : "84" } { "_id" : 3, "a" : "179" }
以下示例匹配第一个文档,其中字段 a
的数值大于 100 并将其删除。
docs = numbers.find_one_and_delete({ "a" => { "$gt" => "100" } }, { "collation" => { "locale" => "en", "numericOrdering" => true } })
执行上述操作后,集合中剩下以下文档
{ "_id" : 1, "a" : "16" } { "_id" : 2, "a" : "84" }
如果不进行排序执行相同的操作,服务器将删除第一个找到的 a
的字典值大于 "100"
的文档。
numbers = client[:numbers] docs = numbers.find_one_and_delete({ "a" => { "$gt" => "100" } })
执行上述操作后,a
等于 "16"
的文档已被删除,集合中剩下以下文档
{ "_id" : 2, "a" : "84" } { "_id" : 3, "a" : "179" }
delete_many()
您可以使用与 Ruby 驱动程序中所有各种批量操作一起使用的排序。
集合 recipes
包含以下文档
{ "_id" : 1, "dish" : "veggie empanadas", "cuisine" : "Spanish" } { "_id" : 2, "dish" : "beef bourgignon", "cuisine" : "French" } { "_id" : 3, "dish" : "chicken molé", "cuisine" : "Mexican" } { "_id" : 4, "dish" : "chicken paillard", "cuisine" : "french" } { "_id" : 5, "dish" : "pozole verde", "cuisine" : "Mexican" }
将排序文档中的 strength
参数设置为 1
或 2
将导致服务器在查询过滤器中忽略大小写。以下示例使用不区分大小写的查询过滤器删除所有字段 cuisine
匹配 French
的记录。
client = Mongo::Client.new([ "127.0.0.1:27017" ], :database => "test") recipes = client[:recipes] docs = recipes.delete_many({ "cuisine" => "French" }, "collation" => { "locale" => "en_US", "strength" => 1 })
上述操作执行后,具有 _id
值为 2
和 4
的文档将从集合中删除。
聚合
要在聚合操作中使用排序,请在聚合选项中指定排序。
以下聚合示例使用名为 names
的集合,将 first_name
字段分组,计算每个组中的结果总数,并按德语电话簿顺序排序结果。
aggregation = names.aggregate( [ { "$group" => { "_id" => "$first_name", "name_count" => { "$sum" => 1 } } }, { "$sort" => { "_id" => 1 } }, ], { "collation" => { "locale" => "de@collation=phonebook" } } ) aggregation.each do |doc| #=> Yields a BSON::Document. end