摘要:排序結(jié)果的條件修改器條件,用戶對(duì)匹配的文檔進(jìn)行更新和必須指定一個(gè)布爾類型,表示是否刪除文檔和必須指定一個(gè)布爾類型,表示返回更新前的文檔還是更新后的文檔,默認(rèn)是更新前的文檔。
插入并保存文檔本文所有內(nèi)容以MongoDB 3.2 為基礎(chǔ)。
插入是添加數(shù)據(jù)的基本方法??梢允褂?b>insert插入一個(gè)文檔:
db.foo.insert({"bar": "baz"})批量插入
使用批量插入,可以加快插入的速度。我們可以使用insertMany來實(shí)現(xiàn)批量插入,它接收一個(gè)文檔數(shù)組作為參數(shù)
db.foo.insertMany([{"id": 1}, {"id": 2}, {"id": 3}])
一次發(fā)送數(shù)十、數(shù)百乃至數(shù)千個(gè)文檔會(huì)明顯提高插入的速度。
本方法不能插入多個(gè)文檔到多個(gè)集合中。只能插入多個(gè)文檔到一個(gè)集合中。
但是一次性接受的最大消息長(zhǎng)度是有限制的。每次接受的文檔數(shù)組長(zhǎng)度為1000個(gè)。如果超過,則會(huì)分次進(jìn)行插入。
如果批量插入的時(shí)候,中間有一個(gè)文檔插入失敗,那么前面的文檔插入成功,而后面的文檔則全部插入失敗。
insertMany有第三個(gè)參數(shù)ordered意味著是否執(zhí)行有序或者無序的插入,默認(rèn)為true(執(zhí)行有序插入),如果為false,則插入的時(shí)候會(huì)跳過插入失敗的數(shù)據(jù),繼續(xù)后面數(shù)據(jù)的插入。
插入數(shù)據(jù)的時(shí)候,Mongo只會(huì)對(duì)數(shù)據(jù)進(jìn)行基本的檢查:檢查文檔的格式, 如果沒有 "_id" 字段,就自動(dòng)增加一個(gè); 檢查大小, 所有的文檔都必須小于16MB。這樣的限制主要是為了防止不良的模式設(shè)計(jì), 并且保證性能的一致。
由于MongoDB只進(jìn)行基本的檢查,所以插入非法數(shù)據(jù)非常容易。因此,應(yīng)該只允許信任的源連接數(shù)據(jù)庫。主流語言的驅(qū)動(dòng)程序都胡izai數(shù)據(jù)插入到數(shù)據(jù)庫之前做大量的數(shù)據(jù)檢驗(yàn)(比如文檔是否過大,文檔是否包含非UTF-8字符串,是否使用了不可識(shí)別的類型)。
刪除的命令是:
db.foo.remove({})
上述命令會(huì)刪除foo集合中的所有文檔,但是不會(huì)刪除集合本身,也不會(huì)刪除集合的元信息。
remove()函數(shù)可以接受一個(gè)查詢文檔參數(shù)作為可選參數(shù)。給定這個(gè)參數(shù)之后,只有符合條件的才會(huì)進(jìn)行刪除。
db.foo.remove({"opt-out": true})
刪除文檔是永久性的,不能撤銷,也不能恢復(fù)。
刪除速度刪除文檔通常會(huì)快,但是如果要清空整個(gè)集合。使用"drop"直接刪除這個(gè)集合會(huì)更快,然后再這個(gè)空集合上面重建各項(xiàng)索引。需要注意的是"drop"不能指定任何條件,因?yàn)檎麄€(gè)集合都被刪除,集合的元數(shù)據(jù)都不見了。
更新文檔更新文檔使用的是update,update有兩個(gè)參數(shù),一個(gè)是查詢文檔,需要定位你需要更新的目標(biāo)文件,一個(gè)是修改器文檔,用于說明要對(duì)找到的文檔進(jìn)行那些修改。
更新操作是不可分割的。若是兩個(gè)文檔更新同時(shí)發(fā)生,先到達(dá)服務(wù)器的先執(zhí)行,接著執(zhí)行另外一個(gè),所以,兩個(gè)需要同時(shí)進(jìn)行的更新會(huì)迅速接連完成。此過程不會(huì)破壞文檔。
例如要對(duì)下面的文檔進(jìn)行一個(gè)大的調(diào)整
{ "_id" : ObjectId("57745b2294ec519556ea6040"), "name" : "joe", "friends" : 32.0, "enemies" : 2.0 }
我們希望將friends和enemies兩個(gè)字段移到relationships子文檔中,可以這樣實(shí)現(xiàn)
var joe = db.users.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.users.update({"name": "joe"}, joe);
現(xiàn)在可以用findOne來查看更新后的文檔數(shù)據(jù)。
{ "_id" : ObjectId("57745b2294ec519556ea6040"), "username" : "joe", "relationships" : { "friends" : 32.0, "enemies" : 2.0 } }
這里面有個(gè)問題。就是說,如果不知道有多個(gè)同樣name=joe的文檔的時(shí)候,如果盲目update,會(huì)造成因?yàn)槎鄠€(gè)文檔在替換的時(shí)候,因?yàn)?b>_id重復(fù)了,結(jié)果會(huì)導(dǎo)致更新失敗。這個(gè)時(shí)候,我們可以使用_id來作為限定字段,因?yàn)?b>_id在一個(gè)集合當(dāng)中是唯一的。對(duì)于上面的例子,這才是正確的更新辦法:
db.users.update({"_id": ObjectId("57745b2294ec519556ea6040")}, joe)
使用_id作為查詢條件比使用隨機(jī)字段速度更快,因集合是通過_id來建立的索引。
使用修改器通常文檔只有一部分需要更新。我們可以使用原子性的更新修改器,指定對(duì)文檔中的某些字段進(jìn)行更新。更新修改器是一種特殊的鍵,用來指定復(fù)雜的更新操作。
$set修改器比如用戶資料存儲(chǔ)在下面的文檔里面:
{ "_id" : ObjectId("5778a7e487d2bf26ed1188c4"), "name" : "joe", "age" : 30.0, "sex" : "male", "location" : "Wisconsin" }
比如我們想要添加想要的書籍。我們可以這么執(zhí)行:
db.foo.update({"_id" : ObjectId("5778a7e487d2bf26ed1188c4")}, {"$set": {"favorite book": "War and Peace"}})
然后文檔就有了favorite book鍵。$set在key存在的時(shí)候就則進(jìn)行覆蓋,如果不存在,則變成新增Key。
{ "_id" : ObjectId("5778a7e487d2bf26ed1188c4"), "name" : "joe", "age" : 30.0, "sex" : "male", "location" : "Wisconsin", "favorite book" : "War and Peace" }
$set可以改變鍵的數(shù)據(jù)類型。比如我們喜歡很多本書。我們可以這么修改。
db.foo.update({"_id" : ObjectId("5778a7e487d2bf26ed1188c4")}, {"$set": {"favorite book": ["Cat"s Cradle", "Foundation Trilogy", "Ender"s Game"]}})
然后用戶不愛看書,可以使用$unset將這個(gè)鍵完全刪除:
db.foo.update({"_id" : ObjectId("5778a7e487d2bf26ed1188c4")}, {"$unset": {"favorite book": 1}})
我們也可以去修改內(nèi)嵌文檔。比如如下文檔:
{ "_id" : ObjectId("577906ca0befef90da41a9c6"), "title" : "A Blog Post", "content" : "...", "author" : { "name" : "joe", "email" : "joe@example.com" } }
db.foo.update({"_id" : ObjectId("577906ca0befef90da41a9c6")}, {"$set": {"author.name": "joe schmoe"}})
查看文檔:
{ "_id" : ObjectId("577906ca0befef90da41a9c6"), "title" : "A Blog Post", "content" : "...", "author" : { "name" : "joe schmoe", "email" : "joe@example.com" } }增加和減少
$inc修改器可以用來增加已有鍵的值,或者該鍵不存在,那么就創(chuàng)建一個(gè)。
比如我們有這么一個(gè)文檔。
{ "_id" : ObjectId("57790cfe0befef90da41a9c7"), "game" : "pinball", "user" : "joe" }
比如我們給這個(gè)文檔增加50
db.foo.update({"_id" : ObjectId("57790cfe0befef90da41a9c7")}, {"$inc": {"score": 50}})數(shù)組追加元素
{ "_id" : ObjectId("5794a4f679b354ae7c0dccad"), "title" : "a blog post", "content" : "xxx" }
我們現(xiàn)在要對(duì)這個(gè)文檔增加評(píng)論:
db.foo.update({"_id": ObjectId("5794a4f679b354ae7c0dccad")}, {"$push": {"comments": {"name": "joe", "email": "joe@example.com", "content": "nice post."}}})
我們?cè)僖淮尾榭丛撐臋n,就變成了這樣:
{ "_id" : ObjectId("5794a4f679b354ae7c0dccad"), "title" : "a blog post", "content" : "xxx", "comments" : [ { "name" : "joe", "email" : "joe@example.com", "content" : "nice post." } ] }
如果comment鍵不存在,它會(huì)創(chuàng)建一個(gè)值為數(shù)組的comment鍵,并向數(shù)組中添加一條評(píng)論。
如果要同時(shí)添加多條評(píng)論,我們還可以這么辦:
db.foo.update({"_id": ObjectId("5794a4f679b354ae7c0dccad")}, { "$push": { "comments": { "$each": [ {"name": "joe", "email": "joe@example.com", "content": "nice post1."}, {"name": "joe", "email": "joe@example.com", "content": "nice post2."} ] } } })
查看一下文檔,就發(fā)現(xiàn)已經(jīng)同時(shí)添加了兩條評(píng)論:
{ "_id" : ObjectId("5794a4f679b354ae7c0dccad"), "title" : "a blog post", "content" : "xxx", "comments" : [ { "name" : "joe", "email" : "joe@example.com", "content" : "nice post." }, { "name" : "joe", "email" : "joe@example.com", "content" : "nice post1." }, { "name" : "joe", "email" : "joe@example.com", "content" : "nice post2." } ] }
如果想讓我們的comment最大只能存儲(chǔ)4條評(píng)論,我們將$slice和$push組合在一起使用,這樣就可以保證數(shù)組不會(huì)超過設(shè)定好的最大長(zhǎng)度:
db.foo.update({"_id": ObjectId("5794a4f679b354ae7c0dccad")}, { "$push": { "comments": { "$each": [ {"name": "joe", "email": "joe@example.com", "content": "nice post1."}, {"name": "joe", "email": "joe@example.com", "content": "nice post2."} ], "$slice": -4 } } })
{ "_id" : ObjectId("5794a4f679b354ae7c0dccad"), "title" : "a blog post", "content" : "xxx", "comments" : [ { "name" : "joe", "email" : "joe@example.com", "content" : "nice post1." }, { "name" : "joe", "email" : "joe@example.com", "content" : "nice post2." }, { "name" : "joe", "email" : "joe@example.com", "content" : "nice post1." }, { "name" : "joe", "email" : "joe@example.com", "content" : "nice post2." } ] }
我們發(fā)現(xiàn)最開始插入的那條評(píng)論已經(jīng)不存在了。只保存了最后插入的4條評(píng)論。如果我們限制數(shù)組只包含最后插入的10個(gè)元素。$slice就必須是負(fù)整數(shù)。$slice如果是正的,那么只會(huì)保存最開始插入的4條評(píng)論。
將數(shù)組作為數(shù)據(jù)集使用如果我們將數(shù)組作為數(shù)據(jù)集使用,保證數(shù)組內(nèi)的元素不會(huì)重復(fù)。我們可以使用$addToSet來實(shí)現(xiàn)。
比如我們有下面這個(gè)文檔:
{ "_id" : ObjectId("5794ad1279b354ae7c0dccae"), "username" : "joe", "emails" : [ "joe@example.com", "joe@gmail.com", "joe@yahoo.com" ] }
比如我們要給這個(gè)文檔添加新的郵件地址,我們可以使用$addToSet來實(shí)現(xiàn)避免插入重復(fù)地址:
db.foo.update({"_id" : ObjectId("5794ad1279b354ae7c0dccae")}, { "$addToSet": { "emails": { "$each":[ "joe@hotmail.com", "joe@yahoo.com" ] } } })
我們向文檔中插入兩個(gè)郵箱,我們查看一下文檔,我們發(fā)現(xiàn)數(shù)量只是增加了一個(gè)。
{ "_id" : ObjectId("5794ad1279b354ae7c0dccae"), "username" : "joe", "emails" : [ "joe@example.com", "joe@gmail.com", "joe@yahoo.com", "joe@hotmail.com" ] }刪除元素
比如上個(gè)文檔,我們需要?jiǎng)h除emails的一個(gè)有郵箱。我們可以使用$pop來刪除。比如{"$pop": {"emails": 1}}就是從末尾刪除一個(gè)元素,而{"$pop": {"emails": 2}}則是從頭部進(jìn)行刪除。
而比如我們要根據(jù)條件來刪除數(shù)組中的元素,而不是位置。我們可以使用$pull,比如我們刪除joe@yahoo.com,我們可以執(zhí)行下面的命令:
db.foo.update({"_id" : ObjectId("5794ad1279b354ae7c0dccae")}, { "$pull": { "emails" : "joe@yahoo.com" } })
我們查看一下文檔:
{ "_id" : ObjectId("5794ad1279b354ae7c0dccae"), "username" : "joe", "emails" : [ "joe@example.com", "joe@gmail.com", "joe@hotmail.com" ] }
比如我們想把emails里面的第一個(gè)元素修改一下。我們這樣:
db.foo.update({"_id" : ObjectId("5794ad1279b354ae7c0dccae")}, { "$set": { "emails.0" : "joes@example.com" } })
這樣就修改成功了:
{ "_id" : ObjectId("5794ad1279b354ae7c0dccae"), "username" : "joe", "emails" : [ "joes@example.com", // 這一行已經(jīng)正確修改 "joe@gmail.com", "joe@hotmail.com" ] }
比如當(dāng)我們不知道我們要修改的值得位置,我們可以使用$來自動(dòng)匹配。
比如我們要修改emails的joe@gmail.com為joes@gmail.com,我們可以這樣辦:
db.foo.update({"_id" : ObjectId("5794ad1279b354ae7c0dccae"), "emails": "joe@gmail.com"}, { "$set": { "emails.$" : "joes@gmail.com" } })
然后文檔就修改成功了:
{ "_id" : ObjectId("5794ad1279b354ae7c0dccae"), "username" : "joe", "emails" : [ "joes@example.com", "joes@gmail.com", "joe@hotmail.com" ] }修改器速度
有的修改器運(yùn)行速度很快,比如$inc,因?yàn)樗恍枰淖兾臋n的大小,只需要將鍵的值修改一下,所以非常快。
但是$push會(huì)改變文檔的大小,所以就會(huì)慢一些($set能在文檔大小不改變的時(shí)候立即修改它,否則性能也會(huì)有所下降)。
將文檔插入到MongoDB中的時(shí)候,依次插入的文檔在磁盤中的位置是相鄰的。如果一個(gè)文檔變大了,之前的位置放不下這個(gè)文檔了,那么文檔就會(huì)被移動(dòng)到集合的另外一個(gè)位置。
如果你的模式在進(jìn)行插入和刪除的時(shí)會(huì)進(jìn)行大量的移動(dòng)或者經(jīng)常打亂數(shù)據(jù),可以使用usePowerOf2Sizes來提高磁盤的復(fù)用率。
db.runCommand({"collMod": "集合名稱", "usePowerOf2Sizes": true})
執(zhí)行該命令之后,以后進(jìn)行的所有空間分配,所得到的塊大小都是2的冪。由于這個(gè)選項(xiàng)會(huì)導(dǎo)致初始空間分配不是那么高效,所以應(yīng)該只在需要經(jīng)常打亂數(shù)據(jù)的集合上面使用。
在一個(gè)只進(jìn)行插入或者原地更新的集合上使用這個(gè)選項(xiàng),會(huì)導(dǎo)致寫入速度變慢。
upsert是一種特殊的更新。要是沒有找到符合更新條件的文檔,就會(huì)以這個(gè)條件和更新文檔為基礎(chǔ)創(chuàng)建一個(gè)新的文檔。如果找到了匹配的文檔,則正常進(jìn)行更新。 upsert非常方便,不必預(yù)置集合,同一套代碼既可以用戶創(chuàng)建文檔,又可以更新文檔。
使用upsert,既可以避免競(jìng)態(tài)問題,又可以縮減代碼量。具體寫法如下:
db.foo.update({"url": "joe"}, {"$inc": {"pageviews": 1}}, true)
update的第三個(gè)參數(shù)表示是否使用upsert,默認(rèn)是false。這行代碼是原子性的,而且特別高效。
有的時(shí)候,我們需要?jiǎng)?chuàng)建文檔的時(shí)候創(chuàng)建一個(gè)字段并為其賦值,但是更新的時(shí)候,我們并不需要更新這個(gè)字段。我們可以這樣辦。比如created_at這個(gè)字段,我們僅僅需要在創(chuàng)建文檔的時(shí)候賦值,不需要進(jìn)行更新,我們可以執(zhí)行下列命令:
db.foo.update({"url": "joe"}, {"$setOnInsert": {"created_at": new Date()}}, true)更新多個(gè)文檔
默認(rèn)情況下,更新只能對(duì)符合匹配條件的第一個(gè)文檔執(zhí)行操作。要是有多個(gè)文檔符合條件,只會(huì)更新第一個(gè)文檔,其他文檔不會(huì)發(fā)生變化。要更新多個(gè)文檔,我們可以把update的第四個(gè)參數(shù)設(shè)置為true。
比如下面的這條命令:
db.foo.update({"birthday": "1978-10-13"}, {"$set": {"gift": "Happy Birthday!"}}, false, ture)
返回被更新的文檔注意:update以后的行為可能會(huì)發(fā)生變化,比如服務(wù)器默認(rèn)只修改一個(gè)文檔變?yōu)槟J(rèn)會(huì)更新所有匹配的文檔。所以建議顯式指定update的行為或者注意MongoDB的版本更新變化
以上的命令并不能返回被更新的文檔。但是我們可以通過執(zhí)行findAndModify命令來獲得被更新的文檔。
首先介紹一下findAndModify命令可以使用的字段:
findAndModify
字符串,集合名稱
query
查詢文檔,用于檢索文檔的條件。
sort
排序結(jié)果的條件
update
修改器條件,用戶對(duì)匹配的文檔進(jìn)行更新(update和remove必須指定一個(gè))
remove
布爾類型,表示是否刪除文檔(update和remove必須指定一個(gè))
new
布爾類型,表示返回更新前的文檔還是更新后的文檔,默認(rèn)是更新前的文檔。
fields
文檔中需要返回的字段(可選)
upsert
布爾類型,值為true表示這是一個(gè)upsert。默認(rèn)是false
注意,update和remove必須有一個(gè),也只能有一個(gè)。要是沒有匹配的文檔,這個(gè)命令會(huì)返回一個(gè)錯(cuò)誤。
比如之前的命令我們就可以這么寫:
db.runCommand({"findAndModify": "foo", "query": {"url": "joe"}, "update": {"$inc": {"pageviews": 1}}, "upsert": true}) //更新文檔 db.runCommand({"findAndModify": "foo", "query": {"url": "joe"}, "remove": true}) //刪除文檔寫入安全機(jī)制
寫入安全是一種客戶端設(shè)置,用于控制寫入的安全級(jí)別。默認(rèn)情況下,插入、更新和刪除都會(huì)一直等待數(shù)據(jù)庫響應(yīng)。然后才會(huì)繼續(xù)執(zhí)行。如果遇到錯(cuò)誤,客戶端會(huì)拋出一個(gè)錯(cuò)誤。
兩種最基本的寫入安全機(jī)制是應(yīng)答式寫入和非應(yīng)答式寫入。應(yīng)答式是默認(rèn)的方式:數(shù)據(jù)庫會(huì)給出響應(yīng),告訴你寫入操作是否執(zhí)行成功。非應(yīng)答式寫入不返回任何響應(yīng),所以無法知道寫入是否成功。
shell與客戶端程序?qū)Ψ菓?yīng)答式寫入的實(shí)際支持不一樣:shell在執(zhí)行非應(yīng)答式寫入后,會(huì)檢查最后一個(gè)操作是否成功,然后才會(huì)向用戶輸出提示信息。因此,如果在集合上執(zhí)行了一系列無效操作,最后又執(zhí)行了一個(gè)有效操作,shell并不會(huì)提示錯(cuò)誤。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/18867.html
摘要:是一個(gè)非關(guān)系型數(shù)據(jù)庫存儲(chǔ)形式為鍵值對(duì)水平擴(kuò)展很容易常作為緩存數(shù)據(jù)庫來使用的存儲(chǔ)文檔稱之為類似對(duì)象字段值可以包含其他的文檔數(shù)組以及文檔數(shù)組和的概念解析概念的概念解釋說明數(shù)據(jù)庫表集合行文檔列域表關(guān)聯(lián)主鍵手動(dòng)添加自動(dòng)創(chuàng)建一進(jìn)入數(shù)據(jù)庫的目錄輸入啟動(dòng) Mongodb 是一個(gè)非關(guān)系型數(shù)據(jù)庫 存儲(chǔ)形式為鍵值對(duì) 水平擴(kuò)展很容易 常作為緩存數(shù)據(jù)庫來使用 Mongodb的存儲(chǔ)文檔稱之為 BSON...
摘要:如果沒有找到找到符合條件的文檔,就會(huì)以這個(gè)條件和更新文檔為基礎(chǔ)新建一個(gè)新的文檔。使用它可以快速方便的對(duì)文檔進(jìn)行更新。更新多個(gè)文檔默認(rèn)情況下,文檔的更新只針對(duì)第一個(gè)匹配到的文檔,多個(gè)條件符合時(shí),其它文檔不會(huì)改變。 what is MongoDB ? 面向文檔的數(shù)據(jù)庫 不再有行的概念,不再有預(yù)定義模式 易于拓展 豐富的功能 索引 聚合 特殊的集合類型 文件存儲(chǔ) 高性能 可以一個(gè)示...
摘要:如果沒有找到找到符合條件的文檔,就會(huì)以這個(gè)條件和更新文檔為基礎(chǔ)新建一個(gè)新的文檔。使用它可以快速方便的對(duì)文檔進(jìn)行更新。更新多個(gè)文檔默認(rèn)情況下,文檔的更新只針對(duì)第一個(gè)匹配到的文檔,多個(gè)條件符合時(shí),其它文檔不會(huì)改變。 what is MongoDB ? 面向文檔的數(shù)據(jù)庫 不再有行的概念,不再有預(yù)定義模式 易于拓展 豐富的功能 索引 聚合 特殊的集合類型 文件存儲(chǔ) 高性能 可以一個(gè)示...
摘要:固定集合可以聲明的容量大小,其行為類似于循環(huán)隊(duì)列。一般來說,固定集合適用于任何想要自動(dòng)淘汰過期屬性的場(chǎng)景。固定集合的優(yōu)點(diǎn)寫入速度提升。固定集合非常實(shí)用與記錄日志等場(chǎng)景。不可以對(duì)固定集合執(zhí)行刪除文檔操作,但可以刪除整個(gè)集合。 一 . 什么是固定集合 MongoDB中有一種特殊類型的集合,值得我們特別留意,那就是固定集合(capped collection)。 固定集合可以聲明collec...
閱讀 2555·2021-10-13 09:40
閱讀 3451·2019-08-30 13:46
閱讀 1191·2019-08-29 14:05
閱讀 3020·2019-08-29 12:48
閱讀 3725·2019-08-26 13:28
閱讀 2218·2019-08-26 11:34
閱讀 2360·2019-08-23 18:11
閱讀 1258·2019-08-23 12:26