本篇文章給大家?guī)淼膬热菔顷P于mongodb中數(shù)組類型的操作(代碼示例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
在mongodb的模式中,我們經(jīng)常將一些數(shù)據(jù)存儲到數(shù)組類型中,即我們常見的嵌套模式設計的一種實現(xiàn)方式。數(shù)組的這種設計實現(xiàn)方式在關系數(shù)據(jù)庫中是沒有或者說不常見的。所以,通過本文我們來梳理一下MongoDB的數(shù)組的相關操作。關于數(shù)組的操作可以分成兩類,一類是數(shù)組操作符,另一個是數(shù)組運算修飾符。
?數(shù)組操作符
操作符 | 實現(xiàn)功能 |
$ | 根據(jù)查詢選擇器定位要更新的文檔 |
$push | 添加值到數(shù)組中 |
$pushAll | 添加數(shù)組到一個數(shù)組中。(將被$rach取代) |
$addToSet |
添加值到數(shù)組中,重復了也不處理 |
$pop | 從數(shù)組中刪除第一個或者最后一個值。 |
$pull | 從數(shù)組中刪除匹配查詢條件的值。 |
$pullAll | 從數(shù)組中刪除多個值。 |
數(shù)組運算修飾符
修飾符 | 實現(xiàn)功能 |
$each | 與$push和$addToSet一起使用來操作多個值。 |
$slice | 與$push和$each一起使用來縮小更新后數(shù)組的大小。 |
$sort | 與$push、$each、$slice一起來排序數(shù)組中的子文檔。 |
1.$push操作符
1.1 語法及功能描述
$push 主要用來向數(shù)組中添加元素。
語法:
{?$push:?{?<field1>:?<value1>,?...?}?}</value1></field1>
默認情況下,它會在數(shù)組尾部添加一個單獨的元素。
1.2 操作案例
假如我們有一個學生成績的集合studentscore,其文檔格式如下:
{?"_id"?:?1,?"name"?:?"xiaoming",?"score"?:?[?{?"math"?:?99,?"english"?:?89?}?]?} {?"_id"?:?2,?"name"?:?"xiaohong",?"score"?:?[?{?"math"?:?98,?"english"?:?96?}?]?}
其中的需求為,更新_id 為1的文檔記錄,在分數(shù)數(shù)組的字段上,添加 物理學的成績,修改代碼為
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修飾符,批量插入
如果一次將多個值添加到數(shù)組中,可結合 數(shù)組修改符??$each 一起使用。
例如,我們將小紅的(_id =2)的物理成績、化學成績、生物成績一起添加到文檔中。執(zhí)行的語句如下:
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 數(shù)組修飾符?$sort 和 $slice的使用
前面講了$each 數(shù)組運算修飾符,那我們再舉一個例子,將剩余的兩個修飾符一起講解了好了($sort 和 $slice)
例如,我們有文檔記錄如下:
{ ???"_id"?:?5, ???"quizzes"?:?[ ??????{?"wk":?1,?"score"?:?10?}, ??????{?"wk":?2,?"score"?:?8?}, ??????{?"wk":?3,?"score"?:?5?}, ??????{?"wk":?4,?"score"?:?6?}??? ??????] ??????}
現(xiàn)在我們,有個需求,就是 首先向文檔的quizzes數(shù)組字段,追加三個記錄,然后,我們再按照score排序,選取數(shù)組中的前三個元素。
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 里添加的,其目的是方便管理經(jīng)常更新的數(shù)組。當向數(shù)組添加值但是不想數(shù)組太大的時候,這個操作符非常有用。它必須與$push、$each操作符一起使用,允許用來剪短數(shù)組的大小、刪除舊的值。
與$slice操作修飾符很像,MongoDB 2.4 新增了$sort操作修飾符,幫助更新數(shù)組。當使用$push和$slice時,有時候要先排序再刪除它們。
2. $pop 操作符
2.1 語法及功能描述
$pop操作符可以實現(xiàn)從數(shù)組中刪除第一個或者是最好一個元素。
{?$pop:?{?<field>:?,?...?}?}</field>
參數(shù)為-1 ,代表要刪除數(shù)組中的第一個元素;參數(shù)為1 ,代表要刪除數(shù)組中的最后一個元素。
2.2 操作案例
例如集合students 中有以下文檔:
{?_id:?1,?scores:?[?8,?9,?10?]?}
我們的需求是要把數(shù)組中的第一個元素(成績?yōu)?)移除,SQL 語句如下:
db.students.update(?{?_id:?1?},?{?$pop:?{?scores:?-1?}?}?)
更新后,文檔如下
{?_id:?1,?scores:?[?9,?10?]?}
繼續(xù)演示,如果在現(xiàn)有的基礎上,我們需要進一步把數(shù)組的最后一個元素移除(成績?yōu)?0),更新的sQL如下:
db.students.update(?{?_id:?1?},?{?$pop:?{?scores:?1?}?}?)
查詢結果 如下:
{?_id:?1,?scores:?[?9?]?}
3.?$pull操作符
3.1 語法及功能描述
$pull是$pop的復雜形式。使用$pull,可以通過值精確指定要刪除的元素。
語法格式
{?$pull:?{?<field1>:?<value>,?<field2>:?<value>,?...?}?}</value></field2></value></field1>
?3.2 操作案例
3.2.1 移除數(shù)組中等于指定值的元素
測試文檔如下:
{ ???_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"?]}
操作要求是將 數(shù)組字段fruits中的“apples”?and?“oranges” 移除,還要將vegetables數(shù)組字段中的”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的數(shù)組字段 沒有apples也沒有oranges,vegetables數(shù)組字段也沒有了carrots。
3.2.2 移除數(shù)組中滿足指定條件的元素
假如我們有一個?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 移除數(shù)組中內嵌子文檔(即此時數(shù)組元素是子文檔,每一個{}中的內容是一個數(shù)組元素)
假設我們有一個關于 調查的集合?survey,其數(shù)據(jù)如下:
{ ???_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 如果數(shù)組類型的元素還內嵌一個數(shù)組(數(shù)組包數(shù)組),就要特別小心了。
此時就要用到?$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數(shù)組字段 移除,移除的條件是 results數(shù)組字段中的answers字段,符合??q?為?2?and?a?大于等于?8。
db.survey.update( ??{?}, ??{?$pull:?{?results:?{?answers:?{?$elemMatch:?{?q:?2,?a:?{?$gte:?8?}?}?}?}?}?}, ??{?multi:?true?} )
更新后的數(shù)據(jù)如下:
{ ???"_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也會往數(shù)組后面添加值,但是它比較特殊:它只會添加數(shù)組里不存在的值。
{?$addToSet:?{?<field1>:?<value1>,?...?}?}</value1></field1>
4.2 操作案例
假如有一個集合?inventory? 格式如下
{?_id:?1,?item:?"polarizing_filter",?tags:?[?"electronics",?"camera"?]?}
?我們希望向向字段?tags 數(shù)組 ,添加一個元素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 數(shù)組,添加元素?“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 注意點
需要注意是,如果添加的元素是數(shù)組格式,則會將新添加的元素保留為數(shù)組(將會出現(xiàn)數(shù)組嵌套數(shù)組)
例如
{?_id:?1,?letters:?["a",?"b"]?}
執(zhí)行的語句如下:
db.test.update( ???{?_id:?1?}, ???{?$addToSet:?{letters:?[?"c",?"d"?]?}?} )
查詢結構顯示為
{?_id:?1,?letters:?[?"a",?"b",?[?"c",?"d"?]?]?}