1.數組的定位修改器
若數組有多個值,只想對其中一部分進行修改.可以通過位置或定位操作符.
如將上篇的email數組的第一個值"295240648@163.com"修改為"295240648@136.com"
db.users.update(
{"userName":"refactor"},
{
"$set":
{
"emails.0":"295240648@136.com"
}
}
)
很多情況下,不預查詢就不知道要修改數組的下標.MongoDB提供了定位操作符"$",用來
定位查詢文檔已經匹配的元素,並進行更新.
2.修改器速度
有的修改器運行較快."$inc"不需要改變文檔的大小,只需要將鍵的值修改一下,所以修改速度很快.
數組修改器可能更改文檔的大小,就會慢一些,"$set"能在文檔大小不發生改變時立即修改,否則效能也會有所下降.
MongoDB預留了些空白給文檔,來適應大小的變化(事實上,系統會根據文檔的通常的大小變化情況來相應
的調整留的空白大小),但是要是超過了原來的空間,最後還是要分配一塊新的空間.空間分配除了會減慢速度,
同時會隨著數組的變長,MongoDB需要更長的時間來遍曆整個數組,對每個數組的修改也會慢下來.
"$push"或者其他數組修改器是推薦使用的.但要是"$push"成為效率瓶頸,就需要將內嵌數組獨立出來,放到
一個單獨的集合裡面.
3.upsert
upsert是一個特殊的更新,要是沒有文檔符合更新條件,就會以這個條件和更新文檔為基礎建立一個新文檔.
如果找到了匹配的文檔,則正常更新.upsert不比預置集合,同一套代碼可以建立,又可以更新文檔.
以前建立的網站計數器,就可以採用upsert的方式.如果不存在就建立文檔,如果存在就更新.
db.users.insert(
{
"url":"http://www.cnblogs.com/refactor",
"pageViews":12345
}
)
使用upsert
db.users.update(
{"url":"http://www.cnblogs.com/refactor"},
{"$inc":{"pageViews":1}},
true
)
注意update的第三個參數的意思是:啟用upsert.
從集合去除:
db.users.remove({"url":"http://www.cnblogs.com/refactor"})
使用upsert
db.users.update(
{"url":"http://www.cnblogs.com/refactor"},
{"$inc":{"pageViews":1}},
true
)
4.save shell
save是一個shell函數,可以在文檔不存在時插入,存在時更新.它只有一個參數:文檔.要是這個文檔有
"_id"鍵,save會調用upsert,否則會調用插入.程式員可以很方便的使用這個函數在shell中修改文檔
可以看出db.users.save(x)和db.users.update({"_id":x._id},x)效果是一樣的.
5.更新多個文檔
預設情況下,更新只能對合格第一個文檔執行操作.要使有多個符合條件文檔都得到更新,可以設定update的
第四個參數為true.
只會更新第一個匹配項
db.users.update(
{"url":"http://www.cnblogs.com/refactor"},
{"$set":{"pageViews":50000}}
)
更新所有匹配項
db.users.update(
{"url":"http://www.cnblogs.com/refactor"},
{"$set":{"pageViews":50000}},
false,
true
)
注意:以後可能會更改update的行為(伺服器可能預設會更新所有匹配的文檔,只有第四個參數為false的時候才會更新
第一個文檔),所以建議每次都顯示表明要不要進行多文檔更新.
想要知道多文檔更新到底更新了多少文檔,可以用getLastError命令,鍵"n"的值就是要的數字.
可以用findAndModify命令來獲得更新的文檔.
6.瞬間完成
插入,刪除和更新這三個操作都是瞬間完成的,因為他們都不需要等待資料庫響應.這不是非同步作業,用戶端將文檔發送給
伺服器後就不管了,用戶端不會收到伺服器端的響應操作,如:伺服器操作失敗.
這個特點的優點是速度快,它只受用戶端發送的速度或網路速度的制約.但這樣也會出現很多問題,用戶端可能會向根本
不存在的伺服器發送文檔等等.
7.安全操作
如果要完成一個電子商系統,如果某人訂購了某物,應用程式需要時間確保訂單順利.當執行時出現了錯誤,還要重來.
MongoDB預設選擇了不安全的版本,因為構建在關係型資料庫的應用程式基底本都不關心返回的代碼,也不會檢查
返回碼,但又得等待這個返回碼,這會造成效能下降.
安全的版本在執行完了操作立即運行getLastError命令,來檢查是否執行成功.驅動程式會等待資料庫響應,然後
適當的處理錯誤,一般會拋出異常.這樣開發人員就能用自己的語言來處理資料庫的錯誤了.要是操作成功,getLastError
會給出額外的資訊作為響應(如:對於更新,刪除文檔,會給出受影響的文檔數量)
安全的代價就是效能.即便忽略用戶端處理異常的開銷(這個開銷一般是重量級的),等待資料庫響應本身的時間比只發送
訊息的時間多一個數量級,所以要權衡資料庫的重要性和速度需求.
8.捕獲常規錯誤
安全操作也是調試資料庫"奇怪"行為的好方法.即便安全操作最後會在生產環境中移除,但是開發過程中還是應該大量的
使用,這樣可以避免很多常見的資料庫使用錯誤,最常見的就是鍵重複的錯誤.
鍵重複的錯誤經常發生在試圖將一個已被佔用"_id"值插入.MongoDB不允許在一個集合裡面有多個"_id"值一樣的文檔,
如果做的是安全插入,發生了鍵重複錯誤,安全檢查會發現這個伺服器錯誤,並拋出異常.在不安全模式下,資料庫沒有響應,
所以根本不知道插入失敗了.
9.請求和串連
資料庫會為每一個MongoDB資料庫連接建立一個隊列,存放這個串連的請求.當用戶端發送一個請求,會被放到隊列的末尾.
只有隊列中的請求都執行完畢,後續的請求才會執行.
注意,每個串連都有獨立的隊列,要是開啟兩個shell,就有兩個資料庫連接.在一個shell中執行插入,之後在另一個shell中進行
查詢不一定能得到插入的文檔,但是在同一個shell中,插入後再執行查詢一定是能查到的.手動複現這個行為不容易,但在繁忙
的伺服器,交錯的插入/尋找就很有可能了.當開發人員用一個線程插入資料,用伊利個線程檢查是否成功插入時,就會經常的遇到
這個問題.有那麼一兩秒時間,好像根本沒有插入資料,但隨後資料又冒出來了.
使用C#的驅動程式要特別注意這種行為,因為驅動程式使用了串連池.為了提高效率,驅動程式和伺服器簡曆了多個串連
(一個串連池),並將請求分散到這些串連中去.好在驅動程式提供了一些機制來確保一系列的請求都由一個串連處理.