1. 程式人生 > >MongoDB文件操作

MongoDB文件操作

參考文獻

一、插入並儲存文件

1.1 insert()方法

    db.COLLECTION_NAME.insert(document)

    insert()方法是向文件中插入資料最基本的方法,該方法引數接受一個文件,將文件加入到目標集合中。

    如將文件{name:"xxx",age:25}插入集合foo中,只需要如下操作:

        db.foo.insert({name:"xxx",age:25})

    就可在集合中插入該文件。

    需要注意的是,因為我們插入的文件中沒有"_id"鍵,所以這個操作會給文件增加一個自動生成的"_id"鍵,然後再將其儲存在資料庫中。這個鍵並不是地址,也不是簡單遞增的,而是通過"時間戳+機器編號+程序編號+序列號"生成,所以每個"_id"都是唯一的。如下圖所示"_id"為:5bbd4dd38f06ac759d5e8a00,就可分解為時間戳(前四位元組):5bbd4dd3 + 機器號(三位元組):8f06ac + 程序編號(兩位元組):759d + 序列號(三位元組):5e8a00 。

1.2 save()方法

    save()是一個shell函式,它不僅僅支援插入操作,還支援更新操作,它只有一個引數:文件,說的更詳細些的話,則是該文件的"_id"鍵的值,如果已有一個文件具有相同的"_id"鍵值,則執行更新操作,具體則是呼叫upsert()函式,否則則呼叫insert()執行更新操作。

  1. db.collection.save(  
  2.    <document>,  
  3.    {  
  4.      writeConcern: <document>  
  5.    }  
  6. )  

1.3 批量插入

    除了insert()方法外,還可使用batchInsert()方法實現批量插入,該函式與insert()方法不同的地方在於,它接受一個文件陣列作為引數。    

例子:在集合foo中插入{name:"aaa",age:20}, {name:"bbb",age:25}, {name:"ccc",age:30}三條文件:

  1. db.foo.batchInsert([{name:"aaa",age:20}, {name:"bbb",age:25}, {name:"ccc",age:30}])  

1.4 插入原理與方法

    當執行資料插入的時候,驅動程式會把資料轉化成BSON格式,然後將資料匯入資料庫。資料庫會解析BSON,並對其進行最基本的檢查:檢查文件的基本結構。如文件大小(應小於16MB),"_id"欄位等。因此非法資料是無法被甄別的,所以需要對資料來源的資料進行判斷,或者在資料插入資料庫之前做資料校驗。

二、刪除文件

2.1 remove()方法

  1. db.collection.remove(  
  2.    <query>,  
  3.    <justOne>  
  4. )  

    MongoDB v2.6版本對remove()函式進行了更新,修改了引數。

  5. db.collection.remove(  
  6.    <query>,  
  7.    {  
  8.      justOne: <boolean>,  
  9.      writeConcern: <document>  
  10.    }  
  11. )  

    該函式的所有引數都為可選引數,如果全為空,則代表刪除集合裡的所有文件。

  • query :(可選)刪除的文件的條件。
  • justOne : (可選)如果設為 true 1,則只刪除一個文件。
  • writeConcern :(可選)丟擲異常的級別。

2.2 deleteOne()以及deleteMany()

    deleteOne()以及deleteMany()可以認為是remove()方法的拆解,deleteOne()刪除滿足條件的一個文件,deleteMany()刪除滿足條件的所有文件

  1. db.collection.deleteOne(  
  2.    <filter>,  
  3.    {  
  4.       writeConcern: <document>,  
  5.       collation: <document>  
  6.    }  
  7. )  
  8. db.collection.deleteMany(  
  9.    <filter>,  
  10.    {  
  11.       writeConcern: <document>,  
  12.       collation: <document>  
  13.    }  
  14. )  

2.3 drop()

    drop()方法並不對文件進行操作,而是直接刪除集合,該函式適用於上文remove()無引數的情況,該函式直接刪除集合比刪除所有的文件效率更高。

  1. db.collection.drop( { writeConcern: <document> } )  

三、文件更新

3.1 原子性

    在MongoDB中,更新單個的文件操作是原子性的。預設情況下,如果一個update()更新多個文件,那麼對每個文件的更新是原子性的,但是對整個update而言則不是原子性的。有可能存在前一個文件更新成功,後面的文件更新失敗的情況。由於單個文件的更新是原子性的,如果兩個更新同時發生,就會出現阻塞,先到的先執行,所以文件最終結果由靠後的操作決定。

3.2 update()方法

  1. db.collection.update(  
  2.    <query>,  
  3.    <update>,  
  4.    {  
  5.      upsert: <boolean>,  
  6.      multi: <boolean>,  
  7.      writeConcern: <document>,  
  8.      collation: <document>,  
  9.      arrayFilters: [ <filterdocument1>, ... ]  
  10.    }  
  11. )  

update()方法有兩個引數,一個是查詢文件,用於定位需要更新的目標文件;另一個是修改器,用於說明要對找到的文件進行哪些修改。

3.3 文件替換

    替換操作是用一個新的文件替換舊的文件,這一般用於修改比較大的情況。該操作需要一箇中間變數來儲存新值,最後再將舊值覆蓋。

    下圖使用該操作完成了文件值的更新操作:將"xi"的資訊替換為"xixi",當然,這存在著更好的方法。

    另外,使用update()更新時最好指定一個唯一的鍵,如"_id",以防匹配到相同的欄位導致跟新失敗。

3.4 修改器

3.4.1 $set

    "$set"可以完成特定字元的修改,如用來指定一個欄位的值。如果該欄位不存在,則建立它。

    下圖對"name":"ahn"文件中的"status"值進行修改,將原來的"A"改為"D"。

    "$set"還可用來修改鍵的型別以及內嵌文件,使用"$unset"還可將鍵刪除。

3.4.2 $inc

    "$inc"可以對資料進行增加或減少,這個操作只針對數字型別,如整形、長整形與雙精度浮點型。如果操作的該鍵不存在,則建立一個。

    如將info集合中name: "wangsan"文件對應的age減2:

3.5 陣列修改器

    "$push"將資料插入陣列末尾,如果沒有該陣列,則建立一個。

    如在info集合中陣列元素的追加,對name為'bob'的文件新增一個數組元素。

    "each""$push"配合使用,可以一次性push多個值。

  1. db.info.update({ "name" : "bob"},{$push: {"detail": {$each: [{"city" : "Beijing"},{ "city" : "Shanghai"}]}}})  

    上訴操作可在"detail" 中插入兩個值。

    "$slice"+"$push"可規定陣列長度,"$slice"的值必須為負整數。

    "$sort"則可根據某欄位的值對所有物件進行排序。

3.6 陣列作為資料集

    "$addToSet"向陣列中新增元素,如果元素已經存在就不新增。

    "$addToSet"+"$set":新增多個不重複的值。

3.7 刪除陣列元素

    "$pop"將陣列看成佇列,每次pop都刪除一個元素。{"$pop":{"key":1}}從陣列末尾刪除一個元素,"key":-1則從頭部刪除一個元素。

    "$pull"可根據條件來刪除元素。如db.foo.update({},{"$pull":{"class":"English"}})可將class陣列中的"English"元素刪除。

3.8 基於位置的陣列修改器

3.8.1 通過位置

    陣列下標可直接作為鍵來選擇元素,且以0開頭。

    如過我們要將上圖文件中detail數組裡第一個元素的"class"元素改為"0701",則可用下面的方法:

  1. db.info.update({ "name" : "bob"},{$set: {"detail.0.class":"0701"}})  

3.8.2 定位操作符

    但很多時候,我們並不知道需要修改的陣列的下標,所以我們就需要使用定位操作符"$",用來定位查詢文件已經匹配的陣列元素,並進行更新。

    如上面的修改"class",使用定位符如下所示:

    另外,定位符只更新匹配到的第一個元素。

3.9 修改器速度

    最初將文件插入到MongoDB時,一次插入的文件在磁碟上的位置是相鄰的,且文件之間沒有多餘的空間。因此當一個文件變大時,原有的位置就無法放下該文件了,所以這個文件就會被移動位置。

    文件建立之初:(該示例源於《MongoDB權威指南》p.43)

    當對中間的文件的資料進行增加時,這個文件就會被移動到文件尾部:

    當MongoDB不得不移動文件時,它會修改集合的填充因子——為每個新文件預留的增長空間。初始化時,填充因子為1,即完全沒有多餘的空間。在執行完上面的操作後,填充因子擴大為1.5,即每個新加入的文件在之後預留自身1/2大小的空間。如果文件更新操作頻繁,移動次數多,填充因子就會增大。反之,不再有文件移動,填充因子就會緩慢減小。

    這也是有時push成為系統瓶頸的原因,文件更新造成文件磁碟結構的變化,導致大量的硬碟讀寫操作。

3.10 多個文件的更新

    預設的update操作只會更新第一個匹配,要對資料進行批量更新,則需要使用update的第四個引數,將其設為true,表示是否更新全部查到的文件。而有第四個就需要第三個,第三個引數也接收bool型別,表示是否要將我們更新的文件作文新文件插入,預設為false。

    例子:將info集合中將所有status為"B"對應的文件值的status全部改成"B+":

參考文獻:

《MongoDB權威指南》 人們郵電出版社

    《NoSQL資料庫原理與應用》 學校編著