MongoDB中陣列型別相關的操作
概述
在MongoDB的模式中,我們經常將一些資料儲存到陣列型別中,即我們常見的巢狀模式設計的一種實現方式。陣列的這種設計實現方式在關係資料庫中是沒有或者說不常見的。所以,通過本文我們來梳理一下MongoDB的陣列的相關操作。關於陣列的操作可以分成兩類,一類是陣列操作符,另一個是陣列運算修飾符。
陣列操作符
操作符 | 實現功能 |
$ | 根據查詢選擇器定位要更新的文件 |
$push | 新增值到陣列中 |
$pushAll | 新增陣列到一個數組中。(將被$rach取代) |
$addToSet |
新增值到陣列中,重複了也不處理 |
$pop | 從陣列中刪除第一個或者最後一個值。 |
$pull | 從陣列中刪除匹配查詢條件的值。 |
$pullAll | 從陣列中刪除多個值。 |
陣列運算修飾符
修飾符 | 實現功能 |
$each | 與$push和$addToSet一起使用來操作多個值。 |
$slice | 與$push和$each一起使用來縮小更新後陣列的大小。 |
$sort | 與$push、$each、$slice一起來排序陣列中的子文件。 |
1.$push操作符
1.1 語法及功能描述
$push 主要用來向陣列中新增元素。
語法:
{ $push: { <field1>: <value1>, ... } }
預設情況下,它會在陣列尾部新增一個單獨的元素。
1.2 操作案例
假如我們有一個學生成績的集合studentscore,其文件格式如下:
{ "_id" : 1, "name" : "xiaoming", "score" : [ { "math" : 99, "english" : 89 } ] } { "_id" : 2, "name" : "xiaohong", "score" : [ { "math" : 98, "english" : 96 } ] }
其中的需求為,更新_id 為1的文件記錄,在分數陣列的欄位上,新增 物理學的成績,修改程式碼為
db.studentscore.update({_id:1},{$push: {score:{"physics":100}}})
修改後,結果查詢如下:
{ "_id" : 1, "name" : "xiaoming", "score" : [ { "math" : 99, "english" : 89 }, { "physics" : 100 } ] } { "_id" : 2, "name" : "xiaohong", "score" : [ { "math" : 98, "english" : 96 } ] }
1.3 結合$each修飾符,批量插入
如果一次將多個值新增到陣列中,可結合 陣列修改符$each 一起使用。
例如,我們將小紅的(_id =2)的物理成績、化學成績、生物成績一起新增到文件中。執行的語句如下:
db.studentscore.update({ _id: 2 }, { $push: { score: { $each: [{ "physics": 100 }, { "chemistry": 90 }, { "biology": 99 }] } } } )
查詢的結果如下:
{ "_id" : 1, "name" : "xiaoming", "score" : [ { "math" : 99, "english" : 89 }, { "physics" : 100 } ] } { "_id" : 2, "name" : "xiaohong", "score" : [ { "math" : 98, "english" : 96 }, { "physics" : 100 }, { "chemistry" : 90 }, { "biology" : 99 } ] }
1.4 陣列修飾符 $sort 和 $slice的使用
前面講了$each 陣列運算修飾符,那我們再舉一個例子,將剩餘的兩個修飾符一起講解了好了($sort 和 $slice)
例如,我們有文件記錄如下:
{ "_id" : 5, "quizzes" : [ { "wk": 1, "score" : 10 }, { "wk": 2, "score" : 8 }, { "wk": 3, "score" : 5 }, { "wk": 4, "score" : 6 } ] }
現在我們,有個需求,就是 首先向文件的quizzes陣列欄位,追加三個記錄,然後,我們再按照score排序,選取陣列中的前三個元素。
db.students.update( { _id: 5 }, { $push: { quizzes: { $each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ], $sort: { score: -1 }, $slice: 3 } } } )
更新後的結果顯示如下:
{ "_id" : 5, "quizzes" : [ { "wk" : 1, "score" : 10 }, { "wk" : 2, "score" : 8 }, { "wk" : 5, "score" : 8 } ] }
$slice操作修飾符是在MongoDB 2.4 裡新增的,其目的是方便管理經常更新的陣列。當向陣列新增值但是不想陣列太大的時候,這個操作符非常有用。它必須與$push、$each操作符一起使用,允許用來剪短陣列的大小、刪除舊的值。
與$slice操作修飾符很像,MongoDB 2.4 新增了$sort操作修飾符,幫助更新陣列。當使用$push和$slice時,有時候要先排序再刪除它們。
2. $pop 操作符
2.1 語法及功能描述
$pop操作符可以實現從陣列中刪除第一個或者是最好一個元素。
{ $pop: { <field>: <-1 | 1>, ... } }
引數為-1 ,代表要刪除陣列中的第一個元素;引數為1 ,代表要刪除陣列中的最後一個元素。
2.2 操作案例
例如集合students 中有以下文件:
{ _id: 1, scores: [ 8, 9, 10 ] }
我們的需求是要把陣列中的第一個元素(成績為8)移除,SQL 語句如下:
db.students.update( { _id: 1 }, { $pop: { scores: -1 } } )
更新後,文件如下
{ _id: 1, scores: [ 9, 10 ] }
繼續演示,如果在現有的基礎上,我們需要進一步把陣列的最後一個元素移除(成績為10),更新的sQL如下:
db.students.update( { _id: 1 }, { $pop: { scores: 1 } } )
查詢結果 如下:
{ _id: 1, scores: [ 9 ] }
3.$pull操作符
3.1 語法及功能描述
$pull是$pop的複雜形式。使用$pull,可以通過值精確指定要刪除的元素。
語法格式
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
3.2 操作案例
3.2.1 移除陣列中等於指定值 的元素
測試文件如下:
{ _id: 1, fruits: [ "apples", "pears", "oranges", "grapes", "bananas" ], vegetables: [ "carrots", "celery", "squash", "carrots" ] } { _id: 2, fruits: [ "plums", "kiwis", "oranges", "bananas", "apples" ], vegetables: [ "broccoli", "zucchini", "carrots", "onions" ] }
操作要求是將 陣列欄位fruits中的"apples"
and "oranges" 移除,還要將vegetables陣列欄位中的"carrots" 移除,其更新語句如下:
db.stores.update( { }, { $pull: { fruits: { $in: [ "apples", "oranges" ] }, vegetables: "carrots" } }, { multi: true } )
更新後的結果如下:
{ "_id" : 1, "fruits" : [ "pears", "grapes", "bananas" ], "vegetables" : [ "celery", "squash" ] } { "_id" : 2, "fruits" : [ "plums", "kiwis", "bananas" ], "vegetables" : [ "broccoli", "zucchini", "onions" ] }
此時,集合文件中,fruit的陣列欄位 沒有apples也沒有
oranges,vegetables陣列欄位也沒有了carrots。
3.2.2 移除陣列中滿足指定條件 的元素
假如我們有一個 profiles 的集合,其文件格式如下:
{ _id: 1, votes: [ 3, 5, 6, 7, 7, 8 ] }
我們要把votes大於等於6的元素移除,其語句如下:
db.profiles.update( { _id: 1 }, { $pull: { votes: { $gte: 6 } } } )
更新後的結果如下:
{ _id: 1, votes: [3,5 ] }
3.2.3 移除陣列中內嵌子文件(即此時陣列元素是子文件,每一個{}中的內容是一個數組元素)
假設我們有一個關於 調查的集合 survey,其資料如下:
{ _id: 1, results: [ { item: "A", score: 5 }, { item: "B", score: 8, comment: "Strongly agree" } ] } { _id: 2, results: [ { item: "C", score: 8, comment: "Strongly agree" }, { item: "B", score: 4 } ] }
需求是將score 為
8
並且 item
為 "B"的元素移除
db.survey.update( { }, { $pull: { results: { score: 8 , item: "B" } } }, { multi: true } )
更新後的文件如下:
{ "_id" : 1, "results" : [ { "item" : "A", "score" : 5 } ] } { "_id" : 2, "results" : [ { "item" : "C", "score" : 8, "comment" : "Strongly agree" }, { "item" : "B", "score" : 4 } ] }
3.2.4 如果陣列型別的元素還內嵌一個數組(陣列包陣列),就要特別小心了。
此時就要用到$elemMatch操作符。
例如 文件格式如下:
{ _id: 1, results: [ { item: "A", score: 5, answers: [ { q: 1, a: 4 }, { q: 2, a: 6 } ] }, { item: "B", score: 8, answers: [ { q: 1, a: 8 }, { q: 2, a: 9 } ] } ] } { _id: 2, results: [ { item: "C", score: 8, answers: [ { q: 1, a: 8 }, { q: 2, a: 7 } ] }, { item: "B", score: 4, answers: [ { q: 1, a: 0 }, { q: 2, a: 8 } ] } ] }
需要將 results陣列欄位 移除,移除的條件是 results陣列欄位中的
answers欄位,符合 q
為 2
and a
大於等於 8。
db.survey.update( { }, { $pull: { results: { answers: { $elemMatch: { q: 2, a: { $gte: 8 } } } } } }, { multi: true } )
更新後的資料如下:
{ "_id" : 1, "results" : [ { "item" : "A", "score" : 5, "answers" : [ { "q" : 1, "a" : 4 }, { "q" : 2, "a" : 6 } ] } ] } { "_id" : 2, "results" : [ { "item" : "C", "score" : 8, "answers" : [ { "q" : 1, "a" : 8 }, { "q" : 2, "a" : 7 } ] } ] }
4.$addToSet
4.1 語法及功能描述
使用$addToSet也會往陣列後面新增值,但是它比較特殊:它只會新增數組裡不存在的值。
{ $addToSet: { <field1>: <value1>, ... } }
4.2 操作案例
假如有一個集合inventory
格式如下
{ _id: 1, item: "polarizing_filter", tags: [ "electronics", "camera" ] }
我們希望向向欄位tags 陣列 ,新增一個元素 accessories,則 更新語句如下:
db.inventory.update( { _id: 1 }, { $addToSet: { tags: "accessories" } } )
更新後的結果為
{ "_id" : 1, "item" : "polarizing_filter", "tags" : [ "electronics", "camera", "accessories" ] }
如果想批量的增加如果元素,我們可以結合$each 操作符一起使用。
例如以下文件
{ _id: 2, item: "cable", tags: [ "electronics", "supplies" ] }
我們想在欄位tags 陣列,新增元素 "camera" , "electronics" ,"accessories",則更新語句如下:
db.inventory.update( { _id: 2 }, { $addToSet: { tags: { $each: [ "camera", "electronics", "accessories" ] } } } )
更新後的結果如下:
{ _id: 2, item: "cable", tags: [ "electronics", "supplies", "camera", "accessories" ] }
4.3 注意點
需要注意是,如果新增的元素是陣列格式,則會將新新增的元素保留為陣列(將會出現陣列巢狀陣列)
例如
{ _id: 1, letters: ["a", "b"] }
執行的語句如下:
db.test.update( { _id: 1 }, { $addToSet: {letters: [ "c", "d" ] } } )
查詢結構顯示為
{ _id: 1, letters: [ "a", "b", [ "c", "d" ] ] }
本文部分例子來自官網及網路,在此感謝。
本文版權歸作者所有,未經作者同意不得轉載, 謝謝配合!!!