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 |
大於(>) | { |
db.test.find( {price : {$gt : 24}} ) | where price > 24 |
小於(<) | { |
db.test.find( {price : {$lt : 24}} ) | where price < 24 |
大於等於(>=) | { |
db.test.find( {price : {$gte : 24}} ) | where price >= 24 |
小於等於(<=) | { |
db.test.find( {price : {$lte : 24}} ) | where price <= 24 |
不等於(!=) | { |
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
-
limit()
用於限制查詢結果的個數,若匹配的結果不到 限制 個數,則返回匹配數量的結果
db.test.find().limit(3)
-
skip()
用於略過指定個數的文件
>db.test.find().skip(1)
-
sort()
用於對查詢結果進行排序,1 是升序,-1 是降序
>db.test.find().sort({"price" : 1})
-
$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 個問題。
-
當呼叫 find() 函式時,Shell 並不立即查詢資料庫,而是等真正開始獲取結果時才傳送查詢請求。
-
遊標物件的每個方法幾乎都會返回遊標物件本身,這樣可以方便進行鏈式函式的呼叫。
-
在 MongoDB Shell 中使用遊標輸出文件包含兩種情況,如果不將 find() 函式返回的遊標賦值給一個區域性變數進行儲存,在預設情況下游標會自動迭代 20 次。如果將 find() 函式返回的遊標賦值給一個區域性變數,則可以使用遊標物件提供的函式進行手動迭代。
-
使用清空後的遊標,進行迭代輸出時,顯示的內容為空。
遊標從建立到被銷燬的整個過程存在的時間,被稱為遊標的生命週期,包括遊標的建立、使用及銷燬三個階段。當客戶端使用 find() 函式向伺服器端發起一次查詢請求時,會在伺服器端建立一個遊標,然後就可以使用遊標函式來操作查詢結果。
以下三種情況會讓遊標被銷燬。
- 客戶端儲存的遊標變數不在作用域內。
- 遊標遍歷完成後,或者客戶端主動傳送終止訊息。
- 在伺服器端 10 分鐘內未對遊標進行操作。
以下語句顯示使用遊標查詢所有文件:
>var cursor = db.test.find()
>while (cursor.hasNext()){
var doc = cursor.next();
print(doc.name); //把每一條資料都單獨拿出來進行逐行的控制
print(doc); //將遊標資料取出來後,其實每行資料返回的都是一個[object BSON]型的內容
printjson(doc); //將遊標獲取的集合以JSON的形式顯示
}