Ruby操作MongoDB(進階二)-CRUD操作
MongDB資料庫的使用離不開CRUD操作。什麼是CRUD,就是建立文件,讀取文件資訊,更新文件和刪除文件。
-
key-value鍵值對標記
在MongoDB的Ruby驅動中,Key_value鍵值多次出現。而且有時會出現語法上的巧合,這取決於在使用的Ruby版本中如何申明。
在文件建立步驟中,1.9及之後版本支援以下語法:
document={name:"Tom",age:20}。
但是如果你使用的是2.2或者更高的版本,你可以用雙引號將你的key包起來。如:
document={"name":"Tom","age":36}
如果你需要使用以"$"開始的MongoDB操作符,例如$set,$gte或者$near,你就必須使用雙引號將其閉合包裹。如果你使用2.2或者更好的Ruby版本,可使用如下寫法:
collection.update_one({name:"Tom"},{"$set":{age:42}})
如果你使用了更早的版本,使用HashRocket符號寫法
collection.update_one({name:"Tom"},{"$set"=>{age:42}})
使用strings和hashrockets來描述鍵值對在任意版本都適用
collection.update_one({"name"=>"Tom"},{"$set"=>{"age":42}})
2. 文件建立-類比關係型資料庫的表格建立
這邊首先講述下,MongoDB中的文件建立與關係型資料庫中表格建立的區別。在MongoDB中插入資料到集合的時候會自動建立文件,而關係型資料庫表格的使用必須基於預先定義好表結構。MongoDB這種機制的好處在於可以不用預先知道文件的結構。具有更好的相容性。
在MongoDB中,在指定了具體的集合名字後,我們使用insert_one()和insert_many()兩個方法來向集合中插入文件資訊。插入操作返回一個包含了插入資訊的Mongo::Operation::Result物件。在2.6及之後的MongoDB版本中,由於使用了寫命令,如果插入失敗,會丟擲異常。2.4版本的MongoDB中,只有在插入黑白且寫的結果大於等於1時才會丟擲異常。
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
result=client[:actors].insert_one({:name=>"TK"})
result.n #返回成功插入的文件數
result=client[:actors].insert_many([
{:name=>"April"},{:name=>'Tom'}
])
result.insert_count #此處返回2,插入兩個文件
3. Decimal128型別數字
在3.4版本中,Decimal128是一個BSON資料型別,它是基於decimal型別使用128位元的浮點數值,可以模擬精確的小數舍入,主要用於處理貨幣型資料,諸如金融和稅收的計算。
下面的例子在inventory集合中插入了一個包含Decimal128型別price域的文件。
client=Mongo::Client.new(['127.0.0.1:27017'],:databse=>'test')
price=BSON::Decimal128.new("428.59")
client[:inventory].insert_one({ "_id"=>1,
"item"=>"26 inch moitor"
"price"=>price
)
成功執行上述語句後,會生成下述文件
{"_id":1,"item":"26 inch monitor","price":NumberDecimal("428.59")}
你也可以通過Ruby的BigDecimal物件建立一個Decimal128的物件,或者通過Decimal128.from_string().
big_decimal=BigDecimal.new(428.79,5)
price=BSON::Decimal128.new(big_decimal)
或者
price=BSON::Decimal128.from_string("428.79")
4. 文件讀取 - 類比資料庫查詢資料
Ruby驅動型別通過find方法為集合的查詢提供了一個流暢的介面。find方法也有多個可用引數。查詢方法對於伺服器來說是一個懶執行的方式。也就是說只有在迭代到對應結果時,在這時查詢才會被分配,並得到一個Mongo::Curor的返回。要想找出滿足查詢規則的所有文件集合,通過find方法加上對應的過濾條件。
client = Mongo::Client.new(['127.0.0.1:27017'],:database="film")
client[:actors].find(:name=>"Tom").each do |document|
end
查詢引數,為了增加查詢時的引數,將一系列合適的方法串在find方法之後。Mongo::Collection::View是一個每次方法呼叫後會新生成的而且不可變的物件。
下表是當使用查詢方法時,可以使用的引數列表資訊,還有相應方法的例子
引數 | 描述 |
allow_patrial_results | 共享叢集模式下使用。如果叢集中一個碎片宕機了,查詢出的結果就是從當前存活的碎片中獲取到的,這樣就可能只獲取到了結果的一部分。 |
batch_size(Integer) | 設定了每執行一次GETMORE操作,遊標返回的每批次的文件個數 |
commont(String) | 查詢的註釋 |
hint(Hash) | 執行查詢時使用index hint優化查詢速度 |
limit(Integer) | 將返回的文件的數量限制為所提供的值 |
max_scan(Integer) | 如果要進行全集掃描,設定文件掃描的最大數值 |
no_cursor_timeout | MongoDB在十分鐘間隔後自動關閉非活動的遊標,通過這個引數可以在伺服器上讓遊標永久存活 |
projection(Hash) | 設定結果中需要包含哪些資訊,剔除哪些資訊。例如client[:actors].find.projection(:name=>1) |
read(Hash) |
僅僅為當前查詢設定讀取首選項 client[:actors].find.read(:mode=>:secondary_preferred) |
show_disk_loc(Boolean) | 讓結果資訊包含文件的位置資訊 |
skip(Integer) | 在查詢結果中跳過指定數目的文件 |
snapshot | 使用快照模式進行查詢 |
sort(Hash) |
確定結果的排序規則 client[:actors].find.sort(:name=>-1) |
附件的查詢引數
4.1 count
獲取文件操作返回的文件總數目
client=Mongo::Client.new(['127.0.0.1:27017'],:database='film')
client[:actors].find(:name=>"Tom").count
4.2 distinct
去除結果中的重複值。可以類比SQL中的distinct操作
client=Mongo::Client.new(['127.0.0.1:27017'],:database='film')
client[:actors].find.distinct(:name)
4.3 tailable cursor
對於獲取到的結果集合,你可能需要在當前遊標已遍歷完所有結果後保持tailable cursor的開啟狀態。下面的例子展示的是tailable cursor的使用方法。
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
client[:actors].drop
client[:actors,capped:true,size:512].create
result=client[:actors].insert_many([{:name=>"Tom"},{:name=>"Alex"}])
enum=client[:actors].find({},:cursor_type=>:tailable_wait).to_enum
while true
doc=enum.text
end
4.4 讀取首選項read preference
該引數設定了在副本集結構中,查詢或相應的命令操作應該傳送給哪個候選成員。它由一個標識特定符號的節點,名為tag_sets的hashes陣列,兩個時間選項(local_threshold,server_selection_timeout)組成。
local_threshold:最近的伺服器和可以傳送指令操作的可用伺服器之間的時間延遲視窗的上限值(單位為秒)。預設值為0.015s或15ms。
server_selection_timeout:伺服器選擇時,丟擲異常前的阻塞時間。預設是30s,也就是30000ms。
更對關於伺服器選擇演算法,請參考後續博文。
讀取首選項引數可以作為客戶端連線的一個引數,也可以作為執行在資料庫之上的命令的引數
#客戶端連線時設定read preference引數,應用於所有的操作上
client = Mongo::Client.new(['127.0.0.1:27017'],read:{:mode=>:secondary,:tag_sets=>[{'dc'=>'nyc'}]})
#對於給定的命令設定讀取首選項引數
client.database.command({:collstats=>'test'},:read=>{:mode=>:secondary,:tag_sets=>[{'dc'=>'nyc'}]})
4.4.1 mode引數
模式引數的取值包含五種,也就是:primary,:secondary,:primary_prefered,:secondary_prefered,:nearest。具體的模式含義,請參考後續博文。
4.4.2 tag_sets引數
tag_sets引數是一串排序的標籤集合,用於控制伺服器選舉時限制伺服器的選舉資格。讀取首選項的標籤集(T)需要匹配伺服器的標籤集(S);如果T是S的子集,也可是相應的伺服器標籤集(S)匹配讀取首選項的標籤集(T).
例如,讀取首選項標籤集{dc:'ny',rack:2}匹配了擁有標籤集{dc:'ny',rack:2,size:'large'}的備選伺服器。空的文件標籤集可以匹配任何伺服器,這是由於空的標籤集是任意標籤集的子集。這也意味著標籤集引數是[{}]時匹配所有的伺服器。
5.文件更新-類似於關係型資料庫的update操作
文件更新可以選擇單個更新或多個一起更新方式,也可以選擇使用findAndModify()命令
5.1 update_one
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
actors=client[:actors]
#find後再modify
result=actors.find(:name=>'Alex').update_one("$inc"=>{:plays=>1})
result.n
#直接update_one
reslut=actors.update_one({:name=>"Alex"},{"$inc"=>{:palys=>1}})
result.n
5.2 update_many
#find後再modify
result =actors.find([:label=>'Hospital']).update_many("$inc"=>{:plays=>1})
result.modified_count
#直接update_many
reslut=actors.update_many({:label=>'Hospital'},{"$inc"=>{:plays=>1}})
result.modified_count
5.3 replace_one
#find後再replace
result =actors.find(:name=>'Aphex Twin').replace_one(:name=>'Richard')
result.modified_count
#直接replace_one
result=actors.replace_one({:name=>'Aphex Twin'},{:name=>'Richard'})
result.modified_count
通過$findAndModify方法來進行文件更新和返回,可以使用find_one_and_delete,find_one_and_replace,find_one_and_update三個方法中的任意一個。你可以在更新操作發生前後均能等到對應的文件資訊。
5.4 find_one_and_delete
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
actors=client[:actors]
actors.find(:name=>'Jose James').find_one_and_delete
5.5 find_one_and_replace
doc=actors.find(:name=>Jose James').find_one_and_replace(:name=>'Jose')
doc
doc=actors.find_one_and_replace({:name=>'Jose James'},{:name=>'Jose'})
doc
doc=actors.find(:name=>'Jose James').find_one_and_replace({:name=>'Jose'},:return_document=>:after)
doc
5.6 find_one_and_update
doc=actors.find(:name='Jose James').find_one_and_update('$set'=>{:name=>'Jose'})
doc
doc=actors.find_one_and_update({:name=>'Jose James'},{'$set'=>{:name=>'Jose'}})
doc
5.7 find_one_and_replace
doc=actors.find(:name=>'Jose James').find_one_and_replace({'$set'=>{:name=>'Jose'}},:return_document=>:after)
doc
doc=actors.find_one_and_replace({:name=>'Jose James'},{'$set'=>{:name=>'Jose'}},return_document=>:after)
doc
6 文件刪除操作Deleting
6.1 delete_one 單個刪除
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
actors=client[:actors]
#find後再刪除
result=actors.find(:name=>'Bob').delete_one
result.deleted_count
#直接delete
result=actors.delete_one({:name=>'Bob'})
result.deleted_count
6.2 delete_many 多個刪除
result=actors.find(:label=>'Mute').delete_many
result.deleted_count
result=actors.delete_many({:label=>'Mute'})
result.deleted_count
至此,Ruby操作MongoDB的CRUD操作。該部分是資料庫的基礎部分。