1. 程式人生 > 實用技巧 >MongoDB文件操作

MongoDB文件操作

目錄

MongoDB 文件操作

文件的資料結構和 JSON 基本一樣。

所有儲存在集合中的資料都是 BSON 格式。

BSON 是一種類似 JSON 的二進位制形式的儲存格式,是 Binary JSON 的簡稱。

插入文件

MongoDB 使用 insert() 或 save() 方法向集合中插入文件,語法如下:

db.COLLECTION_NAME.insert(document)
或
db.COLLECTION_NAME.save(document)
  • save():如果 _id 主鍵存在則更新資料,如果不存在就插入資料。該方法新版本中已廢棄,可以使用 db.collection.insertOne()db.collection.replaceOne() 來代替。
  • insert(): 若插入的資料主鍵已經存在,則會拋 org.springframework.dao.DuplicateKeyException 異常,提示主鍵重複,不儲存當前資料。

3.2 版本之後新增了 db.collection.insertOne() 和 db.collection.insertMany()。

db.collection.insertOne() 用於向集合插入一個新文件,語法格式如下:

db.collection.insertOne(
   <document>,
   {
      writeConcern: <document>
   }
)

db.test.iusertone( { item: "card", qty: 15 } );

db.collection.insertMany() 用於向集合插入一個多個文件,語法格式如下:

db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)

db.test.insertMany([
    { item: "card", qty: 15 },
    { item: "envelope", qty: 20 },
    { item: "stamps", qty:30 }
]);

引數說明:

  • document:要寫入的文件。
  • writeConcern:寫入策略,預設為 1,即要求確認寫操作,0 是不要求。
  • ordered:指定是否按順序寫入,預設 true,按順序寫入。
    • 如果為 true,在陣列中執行文件的有序插入,並且如果其中一個文件發生錯誤,MongoDB 將返回而不處理陣列中的其餘文件;
    • 如果為 false,則執行無序插入,若其中一個文件發生錯誤,則忽略錯誤,繼續處理陣列中的其餘文件。

例項

以下文件可以儲存在 MongoDB 的 student 資料庫 的 col 集合中:

>db.col.insert({name: 'xxx', 
    description: '天資聰穎,好學',
    age: 15,
    sex: '男',
    hobbies: ['小說', '籃球', '游泳']
})

以上例項中 col 是我們的集合名,如果該集合不在該資料庫中, MongoDB 會自動建立該集合並插入文件。

插入不指定 _id 欄位,mongod 將建立 _id 欄位併為其分配唯一的 Objectld 值。

檢視已插入文件:

> db.col.find()
{ "_id" : ObjectId("56064886ade2f21f36b03134"), "name" : "xxx", "description" : "天資聰穎,好學", "age" : 15, "sex" : "男" , "hobbies" : ['小說', '籃球', '游泳'] }
> 

我們也可以將資料定義為一個變數,如下所示:

> document=({name: 'xxx', 
    description: '天資聰穎,好學',
    age: 15,
    sex: '男',
    hobbies: ['小說', '籃球', '游泳'],
});
> db.col.insert(document)
WriteResult({ "nInserted" : 1 })
> 

插入指定 _id 欄位的文件,值 _id 必須在集合中唯一,以避免重複鍵錯誤,程式碼如下:

> db.col.insert(
    { _id: 10, item: "box", qty: 20 }
)
> db.col.find()
{ "_id" : 10, "item" : "box" , "qty": 20 }

有序地插入多條文件:

> db.col.insert([
        {_id:10, item:"pen", price:"20" },
        {_id:12, item:"redpen", price: "30" },
        {_id:11, item:"bluepen", price: "40" }
    ],
    {ordered:true}
)

在設定 ordered:true 時,插入的資料是有序的,如果存在某條待插入文件和集合的某文件 _id 相同的情況,_id 相同的文件與後續文件都將不再插入。在設定 ordered:false 時,除了出錯記錄(包括 _id 重複)外其他的記錄繼續插入。

插入文件你也可以使用 db.col.save(document) 命令。如果不指定 _id 欄位 save() 方法類似於 insert() 方法。如果指定 _id 欄位,則會更新該 _id 的資料。

更新文件

MongoDB 使用 update()save() 方法來更新集合中的文件。接下來讓我們詳細來看下兩個函式的應用及其區別。


update() 方法

update() 方法用於更新已存在的文件。語法格式如下:

db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)

引數說明:

  • query : update的查詢條件,類似sql update查詢內where後面的。
  • update : update的物件和一些更新的操作符(如$,$inc...)等,也可以理解為sql update查詢內set後面的
  • upsert : 可選,這個引數的意思是,如果不存在update的記錄,是否插入這個新的文件,true為插入,預設是false,不插入。
  • multi : 可選,mongodb 預設是false,只更新找到的第一條記錄,如果這個引數為true,就把按條件查出來多條記錄全部更新。
  • writeConcern :可選,丟擲異常的級別。
  • collation:指定語言。

例項

我們在集合 col 中插入如下資料:

>db.col.insert({name: 'xxx', 
    description: '天資聰穎,好學',
    age: 15,
    sex: '男',
    hobbies: ['小說', '籃球', '游泳']
})

接著我們通過 update() 方法來更新姓名(name):

>db.col.update({'name':'xxx'},{$set:{'name':'lili'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })   # 輸出資訊
> db.col.find().pretty()
{
        "_id" : ObjectId("56064f89ade2f21f36b03136"),
        "title" : "lili",
        "description" : "天資聰穎,好學",
        "age" : 15,
        "sex" : "男",
        "hobbies" : [
                "小說",
                "籃球",
                "游泳"
        ]
}
>

以上語句只會修改第一條發現的文件,如果你要修改多條相同的文件,則需要設定 multi 引數為 true。

>db.col.update({'name':'xxx'},{$set:{'name':'lili'}},{multi:true})

save() 方法

save() 方法通過傳入的文件來替換已有文件,_id 主鍵存在就更新,不存在就插入。語法格式如下:

db.collection.save(
   <document>,
   {
     writeConcern: <document>
   }
)

引數說明:

  • document : 文件資料。
  • writeConcern :可選,丟擲異常的級別。

例項

以下例項中我們替換了 _id 為 56064f89ade2f21f36b03136 的文件資料:

>db.col.save({
    "_id" : ObjectId("56064f89ade2f21f36b03136"),
    "name" : "tom",
    "description" : "tom 很調皮",
    "age" : 13,
    "sex" : "男",
    "hobbies" : [
            "遊戲",
            "游泳"
    ]
})

替換成功後,我們可以通過 find() 命令來檢視替換後的資料

>db.col.find().pretty()
{
        "_id" : ObjectId("56064f89ade2f21f36b03136"),
        "name" : "tom",
        "description" : "tom 很調皮",
        "age" : 13,
        "sex" : "男",
        "hobbies" : [
                "遊戲",
                "游泳"
        ]
}
> 

如果使用 insert 插入記錄,若新增資料的主鍵已經存在,則會丟擲 DuplicateKeyException 異常提示主鍵重複,不儲存當前資料。


更多例項

只更新第一條記錄:

db.col.update( { "count" : { $gt : 1 } } , { $set : { "test2" : "OK"} } );

全部更新:

db.col.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true );

只新增第一條:

db.col.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );

全部新增進去:

db.col.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true );

全部更新:

db.col.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );

只更新第一條記錄:

db.col.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );

刪除文件

remove() 方法

語法

remove() 方法的基本語法格式如下所示:

db.collection.remove(
   <query>,
   <justOne>
)

如果你的 MongoDB 是 2.6 版本以後的,語法格式如下:

db.collection.remove(
   <query>,
   {
     justOne: <boolean>,
     writeConcern: <document>
   }
)

引數說明:

  • query :(可選)刪除的文件的條件。
  • justOne : (可選)如果設為 true 或 1,則只刪除一個文件,如果不設定該引數,或使用預設值 false,則刪除所有匹配條件的文件。
  • writeConcern :(可選)丟擲異常的級別。

例項

以下文件我們執行兩次插入操作:

>db.col.insert({name: 'xxx', 
    description: '天資聰穎,好學',
    age: 15,
    sex: '男',
    hobbies: ['小說', '籃球', '游泳']
})

使用 find() 函式查詢資料:

> db.col.find()
{ "_id" : ObjectId("56066169ade2f21f36b03137"), "name" : "xxx", "description" : "天資聰穎,好學", "age" : 15, "sex" : "男", "hobbies" : ['小說', '籃球', '游泳'] }
{ "_id" : ObjectId("5606616dade2f21f36b03138"), "name" : "xxx", "description" : "天資聰穎,好學", "age" : 15, "sex" : "男", "hobbies" : ['小說', '籃球', '游泳'] }

接下來我們移除 name 為 'xxx' 的文件:

>db.col.remove({'name':'xxx'})
WriteResult({ "nRemoved" : 2 })           # 刪除了兩條資料
>db.col.find()
……                                        # 沒有資料

如果你只想刪除第一條找到的記錄可以設定 justOne 為 1,如下所示:

>db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)

如果你想刪除所有資料,可以使用以下方式(類似常規 SQL 的 truncate 命令):

>db.col.remove({})
>db.col.find()
>

delete() 方法

官方推薦使用 deleteOne() 和 deleteMany() 方法刪除文件,語法格式如下:

db.collection.deleteMany ({})
db.collection.deleteMany ({ status : "A" })
db.collection.delete.One ({ status : "D" })

第一條語句刪除集合下所有的文件,第二條語句刪除 status 等於 A 的全部文件,第三條語句刪除 status 等於 D 的一個文件。

查詢文件

find() 簡介

MongoDB 查詢資料的語法格式如下:

db.collection.find(query, projection)
  • query :可選,使用查詢操作符指定查詢條件
  • projection :可選,表示使用投影操作符指定返回的欄位,如果忽略此選項則返回所有欄位。(預設省略)。

如果你需要以易讀的方式來讀取資料,可以使用 pretty() 方法,語法格式如下:

>db.col.find().pretty()

pretty() 方法以格式化的方式來顯示所有文件。

例項

以下例項我們查詢了集合 col 中的資料:

> db.col.find().pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "name" : "xxx",
        "description" : "天資聰穎,好學",
        "age" : 15,
        "sex" : "男",
        "hobbies" : [
                "小說",
                "籃球",
                "游泳"
        ]
}

除了 find() 方法之外,還有一個 findOne() 方法,它只返回一個文件。


查詢條件

​ MongoDB 與 RDBMS 的查詢比較

操作符 格式 例項 與 RDBMS where 語句比較
等於(=) { : {}} db.test.find( {price : 24} ) where price = 24
大於(>) { : {$gt : }} db.test.find( {price : {$gt : 24}} ) where price > 24
小於(<) { : {$lt : }} db.test.find( {price : {$lt : 24}} ) where price < 24
大於等於(>=) { : {$gte : }} db.test.find( {price : {$gte : 24}} ) where price >= 24
小於等於(<=) { : {$lte : }} db.test.find( {price : {$lte : 24}} ) where price <= 24
不等於(!=) { : {$ne : }} db.test.find( {price : {$ne : 24}} ) where price != 24
與(and) {key01 : value01, key02 : value02, ...} db.test.find( {name : "《MongoDB 入門教程》", price : 24} ) where name = "《MongoDB 入門教程》" and price = 24
或(or) {$or : [{key01 : value01}, {key02 : value02}, ...]} db.test.find( {$or:[{name : "《MongoDB 入門教程》"},{price : 24}]} ) where name = "《MongoDB 入門教程》" or price = 24

MongoDB AND 條件

MongoDB 的 find() 方法可以傳入多個鍵(key),每個鍵(key)以逗號隔開,即常規 SQL 的 AND 條件。

語法格式如下:

>db.col.find({key1:value1, key2:value2}).pretty()

例項

> db.col.find({"name":"xxx", "age":15}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "name" : "xxx",
        "description" : "天資聰穎,好學",
        "age" : 15,
        "sex" : "男",
        "hobbies" : [
                "小說",
                "籃球",
                "游泳"
        ]
}

以上例項中類似於 WHERE 語句:WHERE name='xxx' AND age=15


MongoDB OR 條件

MongoDB OR 條件語句使用了關鍵字 $or,語法格式如下:

>db.col.find(
   {
      $or: [
         {key1: value1}, {key2:value2}
      ]
   }
).pretty()

例項

>db.col.find({$or:[{"name":"xxx"},{"age": 16}]}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "name" : "xxx",
        "description" : "天資聰穎,好學",
        "age" : 15,
        "sex" : "男",
        "hobbies" : [
                "小說",
                "籃球",
                "游泳"
        ]
}
>

AND 和 OR 聯合使用

AND 和 OR 聯合使用,類似常規 SQL 語句為: 'where age=15 AND (name= 'xxx' OR sex= '男')'

>db.col.find({"age": 15, $or: [{"name": "xxx"},{"sex": "男"}]}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "name" : "xxx",
        "description" : "天資聰穎,好學",
        "age" : 15,
        "sex" : "男",
        "hobbies" : [
                "小說",
                "籃球",
                "游泳"
        ]
}

特定型別查詢

以 test 集合中以下文件為基礎:

> db.test.find()
    {"_id" : Objectld("5ba7342c7f9318ea62161351"), "name" : "《MongoDB教程》", "price" : 24, "tags" : [ "MongoDB", "NoSQL", "database" ]}
    {"_id" : Objectld("5ba747bd7f9318ea62161352"), "name" : "ava 教程", "price" : 36, "tags" : ["程式語言", "Java語言", "面向物件程式設計語言"]}
    {"_id" : Objectld("5ba75a057f9318ea62161356"), "name" : "王二", "age" : null }

查詢 age 為 null 的欄位的語法格式如下:

> db.test.find({age:null})

此語句不僅匹配出 age 為 null 的文件,其他不同型別的文件也會被查出。這是因為 null 不僅會匹配某個鍵值為 null 的文件,而且還會匹配不包含這個鍵的文件。

查詢陣列:

> db.test.find(
{
    tags:['MongoDB', 'NoSQL', 'database']
}
)
{"_id" : ObjectId("5ba7342c7f9318ea62161351"), "name": "《MongoDB教程》", "price" : 24, "tags" : [ "MongoDB", "NoSQL", "database"]}

查詢有 3 個元素的陣列:

> db.test.find(
{
    tags:{$size:3}
}
)
{"_id" : Objectld("5baf9b6663ba0fb3ccccle77"), "name" : "《MongoDB 教程》", ''price" : 24, "tags" : ["MongoDB","NoSQL", "database"]}
{"_id" : Objectld ("5baf 9bc763ba0fk>3ccccle78"), "name" : "《Java 教程》", "price" : 36, "tags" : ["程式語言", "Java語言", "面向物件程式設計語言"]}

查詢數組裡的某一個值:

> db.test.find(
{
    tags: "MongoDB"
}
)
{"_id" : Objectld("5baf9b6663ba0fb3ccccle77"), "name" : "《MongoDB 教程》", ''price" : 24, "tags" : ["MongoDB","NoSQL", "database"]}

limit() 、skip()、sort() 、$regex

  1. limit()

    用於限制查詢結果的個數,若匹配的結果不到 限制 個數,則返回匹配數量的結果

    db.test.find().limit(3)
    
  2. skip()

    用於略過指定個數的文件

    >db.test.find().skip(1)
    
  3. sort()

    用於對查詢結果進行排序,1 是升序,-1 是降序

    >db.test.find().sort({"price" : 1})
    
  4. $regex

    正則表示式,不同於全文檢索,使用正則表示式無須進行任何配置

    > db.test.find({tags:{$regex:"MongoDB"}})
    {"_id" : Objectld("5baf9b6663ba0fb3ccccle77"), "name" : "《MongoDB 教程》", ''price" : 24, "tags" : ["MongoDB","NoSQL", "database"]}
    

遊標

遊標是指對資料一行一行地進行操作,在 MongoDB 資料庫中對遊標的控制非常簡單,只需使用 firid() 函式就可以返回遊標。

方法名 作用
hasNext 判斷是否有更多的文件
next 用來獲取下一條文件
toArray 將查詢結構放到陣列中
count 查詢的結果為文件的總數量
limit 限制查詢結果返回數量
skip 跳過指定數目的文件
sort 對查詢結果進行排序
objsLeftlnBatch 檢視當前批次剩餘的未被迭代的文件數量
addOption 為遊標設定輔助選項,修改遊標的預設行為
hint 為查詢強制使用指定索引
explain 用於獲取查詢執行過程報告
snapshot 對查詢結果使用快照

使用遊標時,需要注意下面 4 個問題。

  1. 當呼叫 find() 函式時,Shell 並不立即查詢資料庫,而是等真正開始獲取結果時才傳送查詢請求。

  2. 遊標物件的每個方法幾乎都會返回遊標物件本身,這樣可以方便進行鏈式函式的呼叫。

  3. 在 MongoDB Shell 中使用遊標輸出文件包含兩種情況,如果不將 find() 函式返回的遊標賦值給一個區域性變數進行儲存,在預設情況下游標會自動迭代 20 次。如果將 find() 函式返回的遊標賦值給一個區域性變數,則可以使用遊標物件提供的函式進行手動迭代。

  4. 使用清空後的遊標,進行迭代輸出時,顯示的內容為空。

遊標從建立到被銷燬的整個過程存在的時間,被稱為遊標的生命週期,包括遊標的建立、使用及銷燬三個階段。當客戶端使用 find() 函式向伺服器端發起一次查詢請求時,會在伺服器端建立一個遊標,然後就可以使用遊標函式來操作查詢結果。

以下三種情況會讓遊標被銷燬。

  • 客戶端儲存的遊標變數不在作用域內。
  • 遊標遍歷完成後,或者客戶端主動傳送終止訊息。
  • 在伺服器端 10 分鐘內未對遊標進行操作。

以下語句顯示使用遊標查詢所有文件:

>var cursor = db.test.find()
>while (cursor.hasNext()){
    var doc = cursor.next();
    print(doc.name);  //把每一條資料都單獨拿出來進行逐行的控制
    print(doc);  //將遊標資料取出來後,其實每行資料返回的都是一個[object BSON]型的內容
    printjson(doc);  //將遊標獲取的集合以JSON的形式顯示
}