插入:
>db.collectionName.insert({"bar":"baz")}
批量插入:
如果要向集合插入多個文檔,使用批量插入會快一些。
batchInsert函數實現批量插入,它接受一個文檔數組作爲參數。
>db.collectionName.batchInsert([ {"_id:0}, {"_id":1}, {"_id":2} ])
>db.collectionName.find()
{"_id:0}
{"_id":1}
{"_id":2}
刪除文檔:
>db.collectionName.remove({})
上述命令只刪除集合裏面的文檔,並不會刪除集合本身,也不會刪除集合的元信息。
remove函數可以接受一個查詢文檔作爲限定條件作爲可選參數。給定參數後,符合條件的文檔纔會被刪除。
>db.collectionName.remove({"xxxx":true})
刪除數據是永久性的,不能撤銷,也不能恢復。
刪除速度:
刪除文檔通常很快,但是如果要清空集合,使用drop直接刪除集合會更快。
例如,插入測試數據:
>for (var i=0; i < 1000000; i++) {
... db.tmps.insert({"foo":i})
... }
使用remove刪除,並記錄花費時間:
var timeRemoves = function() {
var start = (new Date()).getTime();
db.tmps.remove({});
db.tmps.findOne();//Make sure the remove finishes before continuing
var timeDiff = (new Date()).getTime() - start;
print("Remove took:"+timeDiff+"ms");
}
更新文檔:
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
update有兩個參數,一個是查詢文檔,用於定位需要更新的文檔,另一個是修改器(modifier)文檔,用於說明要對找到的文檔進行哪些修改。
更新操作是不可分割的:若是兩個更新同時發生,先到達服務器的先執行,接着執行令一個。
·文檔替換:
最簡單的更新就是用一個新文檔完全替換匹配的文檔。這適用於進行大規模式遷移的情況。
例:
默認文檔結構:
>db.tmps.findOne()
{
"_id" : ObjectId("54f125773d3fab4bb9d6dc63"),
"Name" : "joe",
"Friends" : 32,
"Enemies" : 2,
"Date" : ISODate("2015-02-28T02:18:21.858Z")
}
寫一個definetmps.js文檔,內容如下:
var replaceupdate = function(){
db.tmps.findOne();
var joe = db.tmps.findOne({"Name":"joe"});
joe.relationships = {"Friends":joe.Friends,"Enemies":joe.Enemies};
joe.Username = joe.Name;
delete joe.Friends;
delete joe.Enemies;
delete joe.Name;
db.tmps.update({"Name":"joe"},joe);
db.tmps.findOne();
}
然後再Shell中加載,並執行函數replaceupdate(),最後驗證文檔結構:
>load("definetmps.js")
true
>replaceupdate()
>db.tmps.findOne()
{
"_id" : ObjectId("54f125773d3fab4bb9d6dc63"),
"Date" : ISODate("2015-02-28T02:18:21.858Z"),
"relationships" : {
"Friends" : 32,
"Enemies" : 2
},
"Username" : "joe"
}
一個常見的錯誤是查詢條件匹配到了多個文檔,然後更新時由於第二個參數存在就產生重複的"_id"值。數據庫就會拋出錯誤,任何文檔都不會更新。
·使用修改器:
通常文檔只會有一部分要更新。可以使用原子性的更新修改器,指定對文檔中的某些字段進行更新。
1."$set"修改器入門:
"$set"用來指定一個字段的值。如果這個字段不存在,則創建它。這對更新模式或增加用戶自定義鍵來說非常方便。
例:存儲用戶資料的文檔,結構如下,
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 32,
"sex" : "male",
"location" : "Wisconsin"
}
我們要添加一個新鍵,用戶喜歡的書籍進去,可以使用"$set":
>db.tmps.update({"_id" : ObjectId("54f131d0f755cba4f8d7cb2a")},
... {"$set" : {"favorite book" : "war and peace"}})
然後我們文檔就有了新鍵:
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 32,
"sex" : "male",
"location" : "Wisconsin",
"favorite book" : "war and peace"
}
這個時候喜歡書的鍵已經存在了,用戶想換一本,可直接通過$set完成更新。
用"$set"甚至可以修改鍵的類型。例如用戶喜歡很多本書,就可以將"favorite book"鍵值變成一個數組:
>db.tmps.update({"_id" : ObjectId("54f131d0f755cba4f8d7cb2a")},
... {"$set" : {"favorite book" : ["book1","book2","book3"]}})
如果用戶不喜歡讀書,可以用"$unset"將這個鍵值完全刪除。
>db.tmps.update({"_id" : ObjectId("54f131d0f755cba4f8d7cb2a")},
... {"$unset" : {"favorite book" : 1}})
也可以用"$set"修改內嵌文檔:
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 32,
"sex" : "male",
"location" : "Wisconsin",
"contact" : {
"email" : "[email protected]",
"pnum" : "13212342112"
}
}
>db.tmps.update({"name":"joe"},
... {"$set":{"contact.email":"[email protected]"}})
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 32,
"sex" : "male",
"location" : "Wisconsin",
"contact" : {
"email" : "[email protected]",
"pnum" : "13212342112"
}
}
2.增加和減少"$inc"
"$inc"修改器用來增加已有鍵的值,改鍵不存在就會創建一個。
"$inc"與"$set"的用法類似,就是專門用來增加和減少數字的。"$inc"只能用於整形、長整形或雙精度浮點型的值。
>db.tmps.update({"name":"joe"},
... {"$inc":{"age":1}})
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 33,
"sex" : "male",
"location" : "Wisconsin",
"contact" : {
"email" : "[email protected]",
"pnum" : "13212342112"
}
}
3.數組修改器
有一大類很重要的修改器可用於操作數組。數組是常用且非常有用的數據結構:它們不僅是可通過索引進行引用的列表,而且還可以作爲數據集(set)來用。
4.添加元素"$push"
如果數組已經存在,"$push"會向已有數組末尾添加一個元素,沒有則創建一個新數組。
如:
>db.tmps.update({"name":"joe"},
... {"$push":{"comments":{"name":"bob","email":"[email protected]"}}})
還添加繼續使用"$push",這是一種比較簡單的"$push"使用形式,也可以將它應用在一些比較複雜的數組操作中。
使用"$each"子操作符,可以通過一次"$push"操作添加多個值。
db.tmps.update({"name":"joe"},
... {"$push":{"comments":{"$each":[{"name":"bob","email":"[email protected]"},{"name":"carlo","email":"[email protected]"}]}}})
PS:通過"$set"的實現:
>db.tmps.update({"name":"joe"},
... {"$set":{"comments":[{"name":"bob","email":"[email protected]"},{"name":"carlo","email":"[email protected]"}]}})
如果希望數組的最大長度是固定的,那麼可以將"$slice"和"$push"組合在一起使用,這樣就可以保證數組不會超出設定好的最大長度,這實際上就得到了一個最多包含N個元素的數組。
>db.tmps.update({"name":"joe"},
... {"$push":{"favoritetop":{
... "$each":[{"name":"book","level":3},
... {"name":"music","level":1},
... {"name":"movie","level":4},
... {"name":"run","level":2}],
... "$slice":-3,
... "$sort":{"level":-1}}}})
注意:不能只將"slice"或者"$sort"與"$push"配合使用,且必須使用"$each"。
5.將數組作爲數據集使用
如果將數組作爲數據集使用,保證數組元素不會重複。可以在查詢文檔中用"$ne"來實現。
(test)>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 43,
"emails" : [
]
}
>db.tmps.update({"emails":{"$ne":"[email protected]"}}, {"$push":{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
>db.tmps.update({"emails":{"$ne":"[email protected]"}}, {"$push":{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
由這裏可以看出,$ne是在查詢中做判斷的,如果判斷內容不存在則執行後面的$push操作。
也可以用"$addToSet"來實現:
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 43,
"emails" : [
]
}
>db.tmps.update({"name":"joe"},
... {"$addToSet":{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
>db.tmps.update({"name":"joe"},
... {"$addToSet":{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
(test)>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 43,
"emails" : [
]
}
將"$addToSet"和"$each"組合起來,可以添加多個不同的值,而使用"$ne"和"$push"組合則不能實現。
>db.tmps.update({"name":"joe"},
... {"$addToSet":{"emails":{"$each":[
... "[email protected]","[email protected]","[email protected]","[email protected]"]}}})
6.刪除元素
有幾個從數組中刪除元素的方法。若是把數組看成隊列或者棧,可以用"$pop"這個修改器從數組任何一端刪除元素。
>db.tmps.update({"name":"joe"},
... {"$pop":{"emails":1}}) //從數組末尾刪除元素。
>db.tmps.update({"name":"joe"}, {"$pop":{"emails":-1}}) //從數組開頭刪除元素。
有時需要基於特定條件來刪除元素,而不僅僅是依據元素位置,這時可以用"$pull"。它會將所有匹配文檔全部刪除,而不是隻刪除一個。對數組[1,1,2,1]執行pull 1,結果就只剩一個元素的數組[2]。
7.基於位置的數組修改器
通過位置或者定位操作符("$"):
數組下標都是以0開始的,可以將下標直接作爲建來選擇元素。
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 43,
"emails" : [
]
}
>db.tmps.update({"name":"joe"},
... {"$set":{"emails.3":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 43,
"emails" : [
]
}
很多情況下,不預先查詢文檔就不能知道要修改數組的下標,爲了解決這個問題,Mongodb提供了定位操作符"$",用來定位查詢已經匹配的數組元素,並進行更新。如下:
>db.blog.findOne()
{
"_id" : ObjectId("54f56483d9c146390ce21c58"),
"title" : "my frist blog.",
"content" : "a b c d e f g ....",
"comments" : [
{
"comment" : "good",
"author" : "joe",
"votes" : 0
},
{
"comment" : "it's ok",
"author" : "john",
"votes" : 2
}
]
}
>db.blog.update({"comments.author":"joe"},
... {"$set":{"comments.$.author":"jim"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
>db.blog.findOne()
{
"_id" : ObjectId("54f56483d9c146390ce21c58"),
"title" : "my frist blog.",
"content" : "a b c d e f g ....",
"comments" : [
{
"comment" : "good",
"author" : "jim",
"votes" : 0
},
{
"comment" : "it's ok",
"author" : "john",
"votes" : 2
}
]
}
注意,定位符只更新第一個匹配元素。
特殊的更新:upsert
upsert更新,要是沒有找到符合更新條件的文檔,就會以這個條件和更新文檔爲基礎創建一個新的文檔。如果找到匹配文檔,則正常更新。
update操作的第三個參數處爲true,則是upsert更新!
db.test.update({"url":"www.example.com"}, {"$inc":{"pageviews":1}},true) // 此爲簡寫
db.test.update({"url":"www.example.com"}, {"$inc":{"pageviews":1}},{upsert:true})
save函數:
使用save函數時,如果文檔不存在,它會自動創建文檔;如果文檔存在,它就更新這個文檔。它只有一個參數:文檔。如果這個文檔有"_id"鍵,save會調用upsert;否則調用insert。
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 43,
"emails" : [
]
}
>var x = db.tmps.findOne()
(test)>x.age = 23
23
>db.tmps.save(x)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
>db.tmps.findOne()
{
"_id" : ObjectId("54f131d0f755cba4f8d7cb2a"),
"name" : "joe",
"age" : 23,
"emails" : [
]
}
更新多個文檔:
默認情況,更新只對匹配條件的第一個文檔執行操作。要更新所有匹配,可以將update的第四個參數設置爲true。
>db.tmps.find()
{ "_id" : ObjectId("54f131d0f755cba4f8d7cb2a"), "name" : "joe", "age" : 23 }
{ "_id" : ObjectId("54f6aa46d9c146390ce21c5f"), "name" : "peter", "age" : 23 }
{ "_id" : ObjectId("54f6aa4cd9c146390ce21c60"), "name" : "carlo", "age" : 23 }
>db.tmps.update({"age":23}, {"$set":{"age":24}},false,true) //簡寫方式
>db.tmps.update({"age":23}, {"$set":{"age":24}},{upsert:false,multi:true})
>db.tmps.find()
{ "_id" : ObjectId("54f131d0f755cba4f8d7cb2a"), "name" : "joe", "age" : 24 }
{ "_id" : ObjectId("54f6aa46d9c146390ce21c5f"), "name" : "peter", "age" : 24 }
{ "_id" : ObjectId("54f6aa4cd9c146390ce21c60"), "name" : "carlo", "age" : 24 }
寫入安全機制(write concern)
是一種客戶端設置,用於控制寫入的安全級別。
PS:內容整理於《Mongodb權威指南》