$slice 如果希望數組的最大長度是固定的,那麼可以將 $slice 和 $push 組合在一起使用,就可以保證數組不會超出設定好的最大長度。$slice 的值必須是負整數。 假設$slice的值為10,如果$push 後的數組的元素個數小於10,那麼所有元素都會保留。反之,只有最後那10個元素會 ...
$slice
如果希望數組的最大長度是固定的,那麼可以將 $slice 和 $push 組合在一起使用,就可以保證數組不會超出設定好的最大長度。$slice 的值必須是負整數。
假設$slice的值為10,如果$push 後的數組的元素個數小於10,那麼所有元素都會保留。反之,只有最後那10個元素會保留。因此,$slice 可以用來在文檔中創建一個隊列。
db.class.insert({"班級":"1班"}) WriteResult({ "nInserted" : 1 }) > db.class.update( ... {"班級":"1班"}, ... {"$push":{"students":{ ... "$each":["zs","ls","ww"], ... "$slice":-5}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.class.findOne() { "_id" : ObjectId("5854b5a0e7d717fcb974637b"), "班級" : "1班", "students" : [ "zs", "ls", "ww" ] } > db.class.update( ... {"班級":"1班"}, ... {"$push":{"students":{ ... "$each":["yyb","rhr","www","qqq","eee","rrr"], ... "$slice":-5}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.class.findOne() { "_id" : ObjectId("5854b5a0e7d717fcb974637b"), "班級" : "1班", "students" : [ "rhr", "www", "qqq", "eee", "rrr" ] } >
也可以在清理元素之前使用$sort,只要向數組中添加子對象就需清理,先排序後保留指定的個數。
> db.class.update({},{ "班級" : "一班"}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.class.update( ... {"班級":"一班"}, ... {"$push":{"students": ... {"$each":[{"name":"aaa","age":1},{"name":"bbb","age":2},{"name":"ccc","age":3}], ... "$slice":-2, ... "$sort":{"age":-1}}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.class.findOne() { "_id" : ObjectId("5854b5a0e7d717fcb974637b"), "班級" : "一班", "students" : [ { "name" : "bbb", "age" : 2 }, { "name" : "aaa", "age" : 1 } ] } >
$ne與$addToSet
如果想將數組作為數據集使用,保證數組內的元素不會重覆。可以在查詢文檔中用$ne或者$addToSet來實現。有些情況$ne根本行不通,有些時候更適合用$addToSet。
> db.papers.insert({"authors cited":["yyb"]}) WriteResult({ "nInserted" : 1 }) > db.papers.update({"authors cited":{"$ne":"Richie"}}, {"$push":{"authors cited":"Richie"}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.papers.findOne() { "_id" : ObjectId("5854c900e7d717fcb974637e"), "authors cited" : [ "yyb", "Richie" ] } > db.papers.update({"authors cited":{"$ne":"Richie"}}, {"$push":{"authors cited":"Richie"}}) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 }) >
db.user.findOne() { "_id" : ObjectId("5854cb40e7d717fcb974637f"), "username" : "joe", "emails" : [ "[email protected]", "[email protected]", "[email protected]" ] } > db.user.update( ... ... {"username":"joe"}, ... ... {"$addToSet":{"emails":"[email protected]"}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 }) > db.user.update( ... ... ... {"username":"joe"}, ... ... ... {"$addToSet":{"emails":"[email protected]"}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.user.findOne() { "_id" : ObjectId("5854cb40e7d717fcb974637f"), "username" : "joe", "emails" : [ "[email protected]", "[email protected]", "[email protected]", "[email protected]" ] } >
將$addToSet和$each組合起來,可以添加多個不同的值。而用$ne和$push組合就不能實現。
$addToSet與$push的區別:前者添加到數組中時會去重,後者不會。
>db.user.insert({ "username" : "joe"}) > db.user.update( ... {"username" : "joe"}, ... ... {"$addToSet": ... {"emails" :{"$each": [ ... "[email protected]", ... "[email protected]", ... "[email protected]", ... "[email protected]", ... "[email protected]"]}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.user.findOne() { "_id" : ObjectId("5854ce5ce7d717fcb9746380"), "username" : "joe", "emails" : [ "[email protected]", "[email protected]", "[email protected]", "[email protected]" ] } >
從數組中刪除元素
$pop
可以從數組任何一端刪除元素。
{“$pop”:{“key”:1}}從數組末尾刪除一個元素
{“$pop”:{“key”:-1}}從數組頭部刪除一個元素
> db.class.findOne() { "_id" : ObjectId("5854b5a0e7d717fcb974637b"), "班級" : "一班", "students" : [ { "name" : "bbb", "age" : 2 }, { "name" : "aaa", "age" : 1 } ] } > db.class.update( ... {"班級" : "一班"}, ... {"$pop":{"students":1}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.class.findOne() { "_id" : ObjectId("5854b5a0e7d717fcb974637b"), "班級" : "一班", "students" : [ { "name" : "bbb", "age" : 2 } ] } >
$pull
有時需要基於特定條件來刪除,而不僅僅是依據元素位置,這時可以使用$pull。$pull會將所有匹配的文檔刪除,而不是只刪除一個。
> db.list.insert( ... {"todo":["dishes","laundry","dry cleaning"]}) WriteResult({ "nInserted" : 1 }) > db.list.update({},{"$pull":{"todo":"laundry"}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.list.findOne() { "_id" : ObjectId("585690afc5b0525a48a441b4"), "todo" : [ "dishes", "dry cleaning" ] } >
數組操作符只能用於包含數組值的鍵。例如:不能將一個整數插入數組,也不能將一個字元串從數組中彈出。要修改標量值,使用$set或$inc。
基於位置的數組修改器
有兩種方法操作數組中的值:通過位置或者定位操作符($)
位置
通過數組位置來操作。數組都是以0開頭的,可以將下標直接作為鍵來選擇元素。
> db.blog.insert( ... { ... "content": "...", ... "comments": [ ... { ... "comment": "good post", ... "author": "john", ... "votes": 0 ... }, ... { ... "comment": "i thought it was too short", ... "author": "claire", ... "votes": 3 ... }, ... { ... "comment": "free watches", ... "author": "alice", ... "votes": -1 ... } ... ] ... }) WriteResult({ "nInserted" : 1 }) > db.blog.update({"content":"..."},{"$inc":{"comments.0.votes":1}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.blog.findOne() { "_id" : ObjectId("585694e4c5b0525a48a441b5"), "content" : "...", "comments" : [ { "comment" : "good post", "author" : "john", "votes" : 1 }, { "comment" : "i thought it was too short", "author" : "claire", "votes" : 3 }, { "comment" : "free watches", "author" : "alice", "votes" : -1 } ] } >
定位操作符$
如果無法知道要修改的數組的下標,可以使用定位操作符$,用來定位查詢文檔已經匹配的元素,併進行更新。
> db.blog.update( ... {"comments.author":"john"}, ... {"$set":{"comments.$.author":"jim"}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.blog.findOne() { "_id" : ObjectId("585694e4c5b0525a48a441b5"), "content" : "...", "comments" : [ { "comment" : "good post", "author" : "jim", "votes" : 1 }, { "comment" : "i thought it was too short", "author" : "claire", "votes" : 3 }, { "comment" : "free watches", "author" : "alice", "votes" : -1 } ] } >
upsert
upsert是update()的第三個參數。表示沒有則創建,有則正常更新。
> db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":1}},true) WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : ObjectId("58569d3cb6687ca8dfad4e01") }) > db.analytics.findOne() { "_id" : ObjectId("58569d3cb6687ca8dfad4e01"), "url" : "/blog", "pageviews" : 1 } > db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":1}},true) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.analytics.findOne() { "_id" : ObjectId("58569d3cb6687ca8dfad4e01"), "url" : "/blog", "pageviews" : 2 } >
$setOnInsert
在創建文檔的同時創建欄位併為它賦值,但是在之後的所有更新操作中在,這個欄位的值都不在改變。
$setOnInsert只會在文檔插入時設置欄位的值。
在預置或者初始化計數器時,或者對於不使用ObjectIds的集合來說,“$setOnInsert”是非常有用的。
> db.user.update({},{"$setOnInsert":{"createAt":new Date()}},true) WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : ObjectId("58569fe1b6687ca8dfad4e02") }) > db.user.findOne() { "_id" : ObjectId("58569fe1b6687ca8dfad4e02"), "createAt" : ISODate("2016-12-18T14:40:33.273Z") } > db.user.update({},{"$setOnInsert":{"createAt":new Date()}},true) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 }) > db.user.findOne() { "_id" : ObjectId("58569fe1b6687ca8dfad4e02"), "createAt" : ISODate("2016-12-18T14:40:33.273Z") } >
save
一個shell函數,不存在創建,反之則更新文檔。
它只有一個參數:文檔。要是這個文檔含有“_id”鍵,save會調用upsert。否則會調用insert。在shell中快速對文檔進行修改。
> db.user.save({"x":10,"y":20}) WriteResult({ "nInserted" : 1 }) > var x=db.user.findOne() > x.num=43 43 > db.user.save(x) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.user.findOne() { "_id" : ObjectId("5856a230c5b0525a48a441be"), "x" : 10, "y" : 20, "num" : 43 }
更新多個文檔
預設情況下,只會更新匹配的第一個文檔。要更新多個文檔,需要將update的第4個參數設置為true。
想要知道多文檔更