2015年1月8日 星期四

3.MongoDB基本操作(Insert document , remove document, drop collection)

  • Document 文件插入

教程視頻



  • 本文結構:
    • 1.基本的插入語句結構
    • 2.基本插入+ writeconcern
    • 3.批量插入文檔 有可能使用 shell 來完成嗎?
    • 4.insert 與 save操作區別
    • 5.Document 文件刪除
    • 6.使用justOne參數,來刪除一筆資料


1.基本的插入語句結構  

db.collection.insert(
   <documents>,
   {
     writeConcern: {
         w:"majority",
         wtimeout:5000
     },
     ordered: <boolean>
   }
)
參數說明

       * <document> 插入的文檔物件
       * writeConcern:文檔寫入等級設定,預設等級設 w:1
          分成5點等級
             
               w:-1     (嚴謹性:非常低);發生資料庫寫入錯誤一慮不回傳
               w:0      (嚴謹性:低)       ;只可以偵測到網路錯誤
               w:1      (嚴謹性:中 預設等級)
               w:1,j:1 (嚴謹性:高)       ;在寫入日誌後才回傳處理過程。
               w:2      (嚴謹性: 高 )     ;這個級別只在replica set的部署模式下生效
           
            備註:w為設定寫入等級 ; j為日誌設定

            關於writeConcern的選項大家可以看一下這篇文章寫的很清楚
            http://kyfxbl.iteye.com/blog/1952941

基本的插入範例

db.employee.insert({
   name:'canred',
   account:'canred',
   country:'tw',
   age:30
})

操作過程1
 > use employee  
 switched to db employee  
 > db.employee.insert({name:'Canred',account:'Canred',country:'tw',age:30})  
 WriteResult({ "nInserted" : 1 })  
 > db.employee.insert({name:'emp1',account:'emp1',country:'us',age:28})  
 WriteResult({ "nInserted" : 1 })  
 > db.employee.insert({name:'emp2',account:'emp2',country:'us',age:28})  
 WriteResult({ "nInserted" : 1 })  
 > db.employee.insert({name:'emp3',account:'emp3',country:'us',age:28})  
 WriteResult({ "nInserted" : 1 })  
 > db.employee.find().pretty()  
 {  
     "_id" : ObjectId("54af3572540eca3abfc91415"),  
     "name" : "Canred",  
     "account" : "Canred",  
     "country" : "tw",  
     "age" : 30  
 }  
 {  
     "_id" : ObjectId("54af358a540eca3abfc91416"),  
     "name" : "emp1",  
     "account" : "emp1",  
     "country" : "us",  
     "age" : 28  
 }  
 {  
     "_id" : ObjectId("54af3591540eca3abfc91417"),  
     "name" : "emp2",  
     "account" : "emp2",  
     "country" : "us",  
     "age" : 28  
 }  
 {  
     "_id" : ObjectId("54af3598540eca3abfc91418"),  
     "name" : "emp3",  
     "account" : "emp3",  
     "country" : "us",  
     "age" : 28  
 }  
 >  

基本插入+ writeconcern 範例
注意當你使用writeConcern的j:1的時侯,要先確定你用啟動mongod 要有先啟動日誌功能。
ex: mongod --dbpath ../data/mydb --journal

db.employee.insert({
   name:'canred',
   account:'canred',
   country:'tw',
   age:30
},{
   writeConcern:{
       w:1,
       j:1
   }
})

2.批量插入文檔 有可能使用 shell 來完成嗎?


    基本上我們想想應該與 插入單個文檔 相同,最多是 來 [ ] 陣列的符號來操作,沒錯就是
    這樣,當然也可以使用 for 語句來 批量插入。

 db.employee.insert(   
   [   
   {name:"Data1"},   
   {name:"Data2"},   
   {name:"Data3"}   
   ])  

    然後我們在使用 db.employee.find() 來看一下資料是不是多了3筆。



3.insert 與 save操作區別


   若存在主鍵,insert() 不做操作,而save() 則更改原來的內容為新內容
   若存在數據有一筆  { _id : 1, " name " : " n1 " }
    insert({ _id : 1, " name " : " n2 " })           //會提示錯誤
    save({ _id : 1, " name " : " n2 " })            //會把n1 改為n2
    save 操作在 _id  找的得的狀況下,會執行更新操作;
    若 _id 找不到的時侯會執行插入操作。

操作過程
 > db.employee.insert({_id:'A',name:'Hello'})  
 WriteResult({ "nInserted" : 1 })  
 > db.employee.insert({_id:'A',name:'Hello'})  
 WriteResult({  
     "nInserted" : 0,  
     "writeError" : {  
         "code" : 11000,  
         "errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicat  
 e key error index: employee.employee.$_id_ dup key: { : \"A\" }"  
     }  
 })  
 > db.employee.save({_id:'A',name:'Hello 2'})  
 WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })  
 > db.employee.find()  
 { "_id" : ObjectId("54af3572540eca3abfc91415"), "name" : "Canred", "account" : "  
 Canred", "country" : "tw", "age" : 30 }  
 { "_id" : ObjectId("54af358a540eca3abfc91416"), "name" : "emp1", "account" : "em  
 p1", "country" : "us", "age" : 28 }  
 { "_id" : ObjectId("54af3591540eca3abfc91417"), "name" : "emp2", "account" : "em  
 p2", "country" : "us", "age" : 28 }  
 { "_id" : ObjectId("54af3598540eca3abfc91418"), "name" : "emp3", "account" : "em  
 p3", "country" : "us", "age" : 28 }  
 { "_id" : ObjectId("54af3960540eca3abfc9141f"), "name" : "Data1" }  
 { "_id" : ObjectId("54af3960540eca3abfc91420"), "name" : "Data2" }  
 { "_id" : ObjectId("54af3960540eca3abfc91421"), "name" : "Data3" }  
 { "_id" : "A", "name" : "Hello 2" }  
 > db.employee.save({_id:'B',name:'Hello 3'})
WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : "B" })


  • Document 文件刪除


1.刪除文檔的語句結構  

db.collection.remove( {條件式},justOne )

參數說明


    * {條件式} :查詢條件

    * justOne :true | false ,設定是否只刪除第一筆文檔

刪除所有文檔範例

可以使用 { } 來表示空的條件 ,也就是表示全部
db.employee.remove({}


根據修件刪除文檔

db.employee.remove( {name:'Canred'} 
在文檔中 若 name 為 Canred ,將全部刪除

使用justOne參數,來刪除一筆資料

db.employee.remove( {name:'Canred'} , true 


  • 刪除collection


使用drop即可完成

1.刪除collection的語句結構   

    db.collection.drop()





參考資料:來源於 http://kyfxbl.iteye.com/blog/1952941

mongodb有一個write concern的設置,作用是保障write operation的可靠性。一般是在client driver裡設置的,和db.getLastError()方法關係很大
一般來說,所有的mongo driver,在執行一個寫操作(insert、update、delete)之後,都會立刻調用db.getLastError()方法。這樣才有機會知道剛才的寫操作是否成功,如果捕獲到錯誤,就可以進行相應的處理。處理邏輯也是完全由client決定的,比如寫入日誌、拋出錯誤、等待一段時間再次嘗試寫入等。作為mongodb server並不關心,server只負責通知client發生了錯誤
這裡有2點需要注意:
1、db.getLastError()方法是由driver負責調用的,所以業務代碼不需要去顯式調用。這點後面還會專門提到
2、driver一定會調用db.getLastError()函數,但是並不一定能捕獲到錯誤。這主要取決於write concern的設置級別,這也是本文的主題

write concern:0(Unacknowledged)

此級別調用的時序圖如下:
driver調用了getLastError()之後,mongod立刻返回結果,然後才實際進行寫操作。所以getLastError()的返回值一定是null,即使之後的Apply發生了錯誤,driver也不知道。使用這個級別的write concern,driver的寫入調用立刻返回,所以性能是最好的,但是可靠性是最差的,因此並不推薦使用。在各平台最新版本的driver中,也不再以0作為默認級別。其實還有一個w:-1的級別,是error ignored,基本上和w:0差不多。區別在於,w:-1不會捕獲任何錯誤,而w:0可以捕獲network error

write concern:1(acknowledged)

此級別調用的時序圖如下:
和Unacknowledged的區別是,現在mongod只有在Apply(實際寫入操作)完成之後,才會返回getLastError()的響應。所以如果寫入時發生錯誤,driver就能捕獲到,並進行處理。這個級別的write concern具備基本可靠性,也是目前mongodb的默認設置級別

write concern:1 & journal:true(Jounaled)

此級別調用的時序圖如下:

Acknowledged級別的write concern也不是絕對可靠的。因為mongodb的Apply操作,是將數據寫入內存,定期通過fsync寫入硬盤。如果在Apply之後,fsync之前mongod掛了,或者甚至server掛了,那持久化實際上是失敗的。但是在w:1的級別下,driver無法捕獲到這種情況下的error(因為response在apply之後就已經返回到driver)
mongod解決這個問題的辦法是使用Journal機制,寫操作在寫入內存之後,還會寫到journal文件中,這樣如果mongod非正常down掉,重啟以後就可以根據journal文件中的內容,來還原寫操作。在64位的mongod下,journal默認是打開的。但是32位的版本,需要用--journal參數來啟動
在driver層面,則是除了設置w:1之外,再設置journal:true或j:true,來捕獲這個情況下的error

write concern:2(Replica Acknowledged)

這個級別只在replica set的部署模式下生效

這個級別下,只有secondary從primary完成了複製之後,getLastError()的結果才會返回。也可以同時設置journal:true或j:true,則還要等journal寫入也成功後才會返回。但是注意,只要primary的journal寫入就會返回,而不需要等待secondary的journal也寫入。類似的也可以設置w:3,表示至少要有3個節點有數據;或者w:majority,表示>1/2的節點有數據。一般小規模的集群就是3節點部署,所以配置w:2就可以了

建議

設置write concern級別,其實就是在寫操作的性能和可靠性之間做權衡。寫操作的等待時間越長,可靠性就越好。對於非關鍵數據,建議使用默認的w:1就可以了,對於關鍵數據,則使用w:1 & j:true比較好。這裡要注意,journal無論如何都是建議打開的,設置j:true,只是說driver調用getLastError()之後是否要等待journal寫入完成再返回。並不是說不設置j:true就關閉了server端的journal







沒有留言:

張貼留言