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