Ruby操作MongoDB(進階七)-排序規則Collations
本篇博文從三個方面進行排序規則Collations的講解。其中包括概覽,使用方式和支持排序的操作。首先我們對排序規則進行一個概覽性的介紹
排序規則概覽
排序規則為特定語言習慣中的字符串比較提供一套規則,例如,在加拿大法語中,給定詞匯的最後一個重音節決定了其排序順序。
考慮下述法語詞匯:
cote < coté < cte < cté
使用加拿大法語排序規則,得到如下排序結果
cote < cte < coté < cté
如果沒有指定排序規則,MongoDB使用簡單的二進制比較排序。按照這樣的規則,上述單詞的排序結果是
cote < coté < cte < cté
2. 排序規則的使用
創建集合和創建索引時,我們可以指定默認的排序規則,也可以為集合及聚合的CRUD操作指定排序規則。對於支持排序規則的操作,如果沒有指定不同的排序規則,MongoDB會使用默認的排序規則。
排序規則參數
‘collation‘ => { ‘locale‘ => <string>, ‘caseLevel‘ => <bool>, ‘caseFirst‘ => <string>, ‘strength‘ => <int>, ‘numericOrdering‘ => <bool>, ‘alternate‘ => <string>, ‘maxVariable‘ => <string>, ‘normalization‘ => <bool>, ‘backwards‘ => <bool>}
唯一一個必須設定的參數是locale。服務器會將該參數轉換為一個 ICU format locale ID。例如,將locale值設定為en_US
代表美式英語,fr_CA 代表加拿大法語。完整的參數值可以查看 MongoDB manual entry。
2.1 為集合指定排序規則
下面的實例在test數據庫上創建了一個contacts的集合,並且給其分配了默認的locale值為fr_CA排序規則。創建集合的時候指定一個排序規則,確保了集合contacts上包含查詢在內的所有操作都會使用fr_CA排序規則,除非操作指定了特定的排序規則。新建集合上的索引也會繼承默認的排序規則,除非創建索引時指定了其他的排序規則。
client=Mongo::Client.new([‘127.0.0.1:27017‘],:database=>‘test‘) client[:contacts,{"collation"=>{"locale"=>"fr_CA"}}]
2.2 為索引指定排序規則
為索引指定排序規則,可以在創建索引的時候指定collation參數,下面的實例在名為address_book集合的name字段域(first_name)上創建索引,並設定為唯一索引,同時設定了默認的排序規則的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" })
而下面的這種查詢就無法使用上面定義的索引,第一種情況是沒有定義排序集合collation屬性;第二種情況是排序集合上多指定了一個strength屬性
client[:address_book].find({"first_name"=>"Adam"}) client[:address_book].find({"first_name"=>"Adam"}, "collation"=>{"locale"=>"en_US","strength"=>2})
3 支持排序規則的操作
MongoDB數據庫中,所有的查詢,更新和刪除方法均支持排序規則。下面列出了一些常用方法:
3.1 find和sort方法
在查詢結果和排序的時候,單個查詢可以指定排序規則。下面的查詢排序的例子,通過將collation的locale屬性設置為de,設定該查詢排序使用基於德語的排序規則
client=Mongo::Client.new([‘127.0.0.1:27017‘],:database=>"test") client[:contacts].find({"city"=>"New York"},{"collation"=>{"locale"=>"de"}}).sort({"name"=>1})
3.2 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方法,但是指定了排序組合,locle屬性設置了[email protected]=phonebook
.
對於區分專有名詞和其他詞匯區別的語言,有些locale屬性包含collation=phonebook可選參數。設定了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" => "[email protected]=phonebook" },:return_document => :after } )
上述操作後的結果如下:
{ "_id" => 3, "first_name" => "Günter", "verified" => true }
3.2 find_one_and_update方法
通過將numericOrdering
參數設置true可以使用比較數字型字符串,比較的方式就是使用字符串對應的數值。例如numbers集合包含下面的文檔:
{ "_id" : 1, "a" : "16" } { "_id" : 2, "a" : "84" } { "_id" : 3, "a" : "179" }
下面的例子是找到一個包含數字型字段的且數值大於100的文檔,並且刪除它
docs=find_one_and_deletes({"a"=>{"$gt"=>100}},{"collation"=>{"locale"=>"end","numericOrdering"=>true}})
執行了上述操作後,文檔中的
{ "_id" : 1, "a" : "16" } { "_id" : 2, "a" : "84" }
仍然存在,但是
{ "_id" : 3, "a" : "179" }
被刪除了。
但是如果同樣的操作,卻不使用排序規則。那麽服務器會找到a的詞匯值大於100的第一個文檔並且刪除它。
這時,文檔中的第一個被刪除了。查詢後的結果如下:
{ "_id" : 2, "a" : "84" } { "_id" : 3, "a" : "179" }
3.3 多條刪除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" }
設置collation中的strength
為1或者2,可以讓服務器在查詢過濾器運行時忽略大小寫,下面的案例使用不區分大小寫的查詢過濾器來進行cuisine
字段匹配了French的文檔的刪除操作。
client=Mongo::Cient.new([‘127.0.0.1:27017‘],:database=>‘test‘) receipes=client[:receipes] docs=delete_many({"cusine"=>"French"},{"collation"=>{"locale"=>"en_US","strength"=>1}})
執行上述指令後,_id值為2和4的文檔被刪除掉了。
3.4 聚合Aggregation
在集合上進行聚合操作,需要設置collation的aggregation字段。下面的聚合實例使用了一個名為names的集合並且將first_name域分到一組,計算了每個分組的結果文檔數,而且通過German phonebook進行排序。
aggregation=names.aggregate( [ {"$group"=>{"$_id"=>"$first_name","name_count"=>{"$sum"=>1}}}, {"$sort"=>{"$id"=>1}} ],{"collection"=>{"locale"=>"[email protected]=phonebook"}}) aggregation.each do |doc| p doc end
本文出自 “techFuture” 博客,謝絕轉載!
Ruby操作MongoDB(進階七)-排序規則Collations