MongoDB 中聚合( aggregate )主要用于處理數(shù)據(jù)(諸如統(tǒng)計(jì)平均值,求和等),并返回計(jì)算后的數(shù)據(jù)結(jié)果,通常由聚合管道操作符和聚合表達(dá)式組合,完成數(shù)據(jù)處理。功能有點(diǎn)類似 Sql 語句中的 sum()、agv() 等。
目錄
第1關(guān):聚合管道操作符將文檔定制格式輸出(一)
常用聚合管道操作符
$project 修改文檔結(jié)構(gòu)輸出
$match 篩選文檔輸出
編程要求
第2關(guān):聚合管道操作符將文檔定制格式輸出(二)?
$limit 限制文檔數(shù)量輸出
$skip 跳過前 n 條文檔輸出
$limit 與 $skip 可以組合使用
$unwind 拆分?jǐn)?shù)組類型字段
$group 分組輸出
$sort 排序輸出
編程要求
第3關(guān):2-2-3聚合表達(dá)式對(duì)文檔數(shù)據(jù)進(jìn)行統(tǒng)計(jì)
聚合表達(dá)式
編程要求
第1關(guān):聚合管道操作符將文檔定制格式輸出(一)
一、本關(guān)任務(wù):按照編程要求,對(duì)集合 educoder 進(jìn)行相應(yīng)的查詢輸出。
二、相關(guān)知識(shí)
為了完成本關(guān)任務(wù),你需要掌握:
1.聚合管道操作符的作用; 2.$project 的用法; 3.$match 的用法。
常用聚合管道操作符
常用的幾個(gè)聚合管道操作符:
操作符 | 作用 |
---|---|
$project | 修改輸入文檔的結(jié)構(gòu)??梢杂脕碇孛⒃黾踊騽h除域,也可以用于創(chuàng)建計(jì)算結(jié)果以及嵌套文檔 |
$match | 用于過濾數(shù)據(jù),只輸出符合條件的文檔。$match使用MongoDB的標(biāo)準(zhǔn)查詢操作 |
$limit | 用來限制MongoDB聚合管道返回的文檔數(shù) |
$skip | 在聚合管道中跳過指定數(shù)量的文檔,并返回余下的文檔 |
$unwind | 將文檔中的某一個(gè)數(shù)組類型字段拆分成多條,每條包含數(shù)組中的一個(gè)值 |
$group | 將集合中的文檔分組,可用于統(tǒng)計(jì)結(jié)果 |
$sort | 將輸入文檔排序后輸出 |
注意:以上操作不會(huì)修改集合的內(nèi)容,只是將集合以指定形式輸出。
例:在數(shù)據(jù)庫 mydb1 有集合 educoder 內(nèi)容如下:
_id | course | author | tags | learning_num |
---|---|---|---|---|
1 | Python表達(dá)式問題求解實(shí)訓(xùn) | 李暾 | Python基礎(chǔ),求解 | 1882 |
2 | Java語言之基本語法 | 余躍 | Java基礎(chǔ),語法 | 814 |
3 | Python面向?qū)ο缶幊虒?shí)訓(xùn) | 李暾 | Python基礎(chǔ),面向?qū)ο?/td> | 143 |
4 | Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1) | prophet5 | Android,物聯(lián)網(wǎng),移動(dòng)開發(fā) | 207 |
$project 修改文檔結(jié)構(gòu)輸出
有時(shí)候我們并不會(huì)用到文檔的全部?jī)?nèi)容,只是使用其中幾列,這時(shí)候就可以使用 $project 進(jìn)行操作;或者有時(shí)候要重命名鍵值(列名),也可以使用 $project。
對(duì)集合 educoder 進(jìn)行操作:
use mydb1
db.educoder.insert([
{_id:1,course:'Python表達(dá)式問題求解實(shí)訓(xùn)',author:'李暾',tags:['Python基礎(chǔ)','求解'],learning_num:1882},
{_id:2,course:'Java語言之基本語法',author:'余躍',tags:['Java基礎(chǔ)','語法'],learning_num:814},
{_id:3,course:'Python面向?qū)ο缶幊虒?shí)訓(xùn)',author:'李暾',tags:['Python基礎(chǔ)','面向?qū)ο?],learning_num:143},
{_id:4,course:'Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)',author:'prophet5',tags:['Android','物聯(lián)網(wǎng)','移動(dòng)開發(fā)'],learning_num:207}])
db.educoder.find()
此時(shí)可以看到: (我們已經(jīng)成功插入4條數(shù)據(jù))
-
只輸出作者 author 和學(xué)習(xí)人數(shù) learning_num 信息,
_id
也不要不顯示(_id
默認(rèn)是顯示的):db.educoder.aggregate({$project:{_id:0,author:1,learning_num:1}})
0 為不顯示,非 0 為顯示。? -
重命名字段名(把 learning_num 重命名為 num):
db.educoder.aggregate({$project:{course:1,authoe:1,tags:1,num:'$learning_num'}})
?????????
$match 篩選文檔輸出
有時(shí)候我們要在集合中篩選出符合特定條件的文檔,這時(shí)候使用 $match 便可以很快實(shí)現(xiàn)。
只輸出作者為“李暾”的文檔:
db.educoder.aggregate({$match:{author:'李暾'}})
???????????????????????????????????????????????????????????????????????????????????????
編程要求
為了減少你的工作量,給出以下文檔內(nèi)容:
{
_id:1,
course:'Python表達(dá)式問題求解實(shí)訓(xùn)',
author:'李暾',
tags:['Python基礎(chǔ)','求解'],
learning_num:1882
},
{
_id:2,
course:'Java語言之基本語法',
author:'余躍',
tags:['Java基礎(chǔ)','語法'],
learning_num:814
},
{
_id:3,
course:'Python面向?qū)ο缶幊虒?shí)訓(xùn)',
author:'李暾',
tags:['Python基礎(chǔ)','面向?qū)ο?],
learning_num:143
},
{
_id:4,
course:'Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)',
author:'prophet5',
tags:['Android','物聯(lián)網(wǎng)','移動(dòng)開發(fā)'],
learning_num:207
}
先在命令行中操作,將上述文檔插入數(shù)據(jù)庫 test1 中的集合 educoder 中,然后仿照例子中的查詢方法,再在右側(cè)代碼欄 Begin-End 的中按要求輸入符合以下兩條要求的命令,以分號(hào);
隔開(由于測(cè)試需要,請(qǐng)?jiān)诖a里$
符號(hào)前添加轉(zhuǎn)義符\
,不需要有空格,格式如:\$
,平時(shí)在命令行操作不需要):
-
文檔輸出時(shí)只保留 course 和 learning_num 字段(
_id
也不要保留); -
輸出學(xué)習(xí)人數(shù) learning_num 為1882檔。
具體的返回結(jié)果,請(qǐng)查看測(cè)試集。文章來源:http://www.zghlxwxcb.cn/news/detail-486606.html
> use test1
switched to db test1
> db.educoder.insert({_id:1,course:'Python表達(dá)式問題求解實(shí)訓(xùn)',author:'李暾',tags:['Python基礎(chǔ)','求解'],learning_num:1882})
WriteResult({ "nInserted" : 1 })
> db.educoder.insert({_id:2,course:'Java語言之基本語法',author:'余躍',tags:['Java基礎(chǔ)','語法'],learning_num:814})
WriteResult({ "nInserted" : 1 })
> db.educoder.insert({_id:3,course:'Python面向?qū)ο缶幊虒?shí)訓(xùn)',author:'李暾',tags:['Python基礎(chǔ)','面向?qū)ο?],learning_num:143})
WriteResult({ "nInserted" : 1 })
> db.educoder.insert({_id:4,course:'Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)',author:'prophet5',tags:['Android','物聯(lián)網(wǎng)','移動(dòng)開發(fā)'],learning_num:207})
WriteResult({ "nInserted" : 1 })
> db.educoder.find()
{ "_id" : 1, "course" : "Python表達(dá)式問題求解實(shí)訓(xùn)", "author" : "李暾", "tags" : [ "Python基礎(chǔ)", "求解" ], "learning_num" : 1882 }
{ "_id" : 2, "course" : "Java語言之基本語法", "author" : "余躍", "tags" : [ "Java基礎(chǔ)", "語法" ], "learning_num" : 814 }
{ "_id" : 3, "course" : "Python面向?qū)ο缶幊虒?shí)訓(xùn)", "author" : "李暾", "tags" : [ "Python基礎(chǔ)", "面向?qū)ο? ], "learning_num" : 143 }
{ "_id" : 4, "course" : "Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)", "author" : "prophet5", "tags" : [ "Android", "物聯(lián)網(wǎng)", "移動(dòng)開發(fā)" ], "learning_num" : 207 }
> db.educoder.aggregate({$project:{_id:0,course:1,learning_num:1}})
{ "course" : "Python表達(dá)式問題求解實(shí)訓(xùn)", "learning_num" : 1882 }
{ "course" : "Java語言之基本語法", "learning_num" : 814 }
{ "course" : "Python面向?qū)ο缶幊虒?shí)訓(xùn)", "learning_num" : 143 }
{ "course" : "Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)", "learning_num" : 207 }
> db.educoder.aggregate({$match:{learning_num:1882}})
{ "_id" : 1, "course" : "Python表達(dá)式問題求解實(shí)訓(xùn)", "author" : "李暾", "tags" : [ "Python基礎(chǔ)", "求解" ], "learning_num" : 1882 }
第2關(guān):聚合管道操作符將文檔定制格式輸出(二)?
一、本關(guān)任務(wù):按照編程要求,對(duì)集合 educoder 進(jìn)行相應(yīng)的查詢輸出。
二、相關(guān)知識(shí)
上一關(guān)已經(jīng)了解了 $project 和 $match 的用法,本關(guān)就介紹剩余管道操作符的用法。
例:在數(shù)據(jù)庫 mydb1 有集合 educoder 內(nèi)容如下:
_id | course | author | tags | learning_num |
---|---|---|---|---|
1 | Python表達(dá)式問題求解實(shí)訓(xùn) | 李暾 | Python基礎(chǔ),求解 | 1882 |
2 | Java語言之基本語法 | 余躍 | Java基礎(chǔ),語法 | 814 |
3 | Python面向?qū)ο缶幊虒?shí)訓(xùn) | 李暾 | Python基礎(chǔ),面向?qū)ο?/td> | 143 |
4 | Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1) | prophet5 | Android,物聯(lián)網(wǎng),移動(dòng)開發(fā) | 207 |
先插入數(shù)據(jù),方法見第一關(guān);
$limit 限制文檔數(shù)量輸出
有時(shí)候集合中文檔數(shù)量太大,我們只想選取前幾行查看一下,這時(shí)候就可以用 $limit,輸出前2條文檔:
db.educoder.aggregate({$limit:2})
???????????????????????????????????????????????????????????????????????????????????????
$skip 跳過前 n 條文檔輸出
與 $limit 相反,$skip 是跳過前 n 條文檔,顯示剩余文檔。
將集合 educoder 中的前兩條文檔跳過,顯示剩余文檔:
db.educoder.aggregate({$skip:2})
???????????????????????????????????????????????????????????????????????????????????????
- $skip 接受一個(gè)數(shù)字 n,表示丟棄結(jié)果集中的前 n 個(gè)文檔;
$limit 與 $skip 可以組合使用
db.educoder.aggregate([{$skip:1},{$limit:2}])?? #跳過第一條,顯示前兩條,也就是顯示第2-3條文檔
db.educoder.aggregate([{$limit:2},{$skip:1}])
?? #顯示前兩條,跳過第一條,也就是顯示第2條文檔
$unwind 拆分?jǐn)?shù)組類型字段
將 educoder 中的 tags 字段拆分成多條,每條包含數(shù)組中的一個(gè)值:
db.educoder.aggregate({$unwind:'$tags'})
????????????????????????????????????????????????????????????????????????????????????????
$group 分組輸出
該操作比較常用,因?yàn)槲臋n分組后利于我們的統(tǒng)計(jì)。比如,按照作者分組我們就可以統(tǒng)計(jì)出該集合總共有幾個(gè)作者。
在集合 educoder 中,按作者分組:
db.educoder.aggregate({$group:{_id:'$author'}})
??????????????????????????????????????????????????????????????????
$sort 排序輸出
按照學(xué)習(xí)人數(shù) learning_num 降序排序輸出文檔:
db.educoder.aggregate({$sort:{learning_num:-1}})
-1 代表降序排序, 1 代表升序排序。
編程要求
為了減少你的工作量,給出以下文檔內(nèi)容:
{
_id:1,
course:'Python表達(dá)式問題求解實(shí)訓(xùn)',
author:'李暾',
tags:['Python基礎(chǔ)','求解'],
learning_num:1882
},
{
_id:2,
course:'Java語言之基本語法',
author:'余躍',
tags:['Java基礎(chǔ)','語法'],
learning_num:814
},
{
_id:3,
course:'Python面向?qū)ο缶幊虒?shí)訓(xùn)',
author:'李暾',
tags:['Python基礎(chǔ)','面向?qū)ο?],
learning_num:143
},
{
_id:4,
course:'Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)',
author:'prophet5',
tags:['Android','物聯(lián)網(wǎng)','移動(dòng)開發(fā)'],
learning_num:207
}
先在命令行中操作,將上述文檔插入數(shù)據(jù)庫 test2 中的集合 educoder 中,然后仿照例子中的查詢方法,再在右側(cè)代碼欄 Begin-End 中按要求輸入符合以下3條要求的命令,以分號(hào);
隔開(由于測(cè)試需要,請(qǐng)?jiān)诖a里$
符號(hào)前添加轉(zhuǎn)義符\
,不需要有空格,格式如:\$
,平時(shí)在命令行操作不需要):
-
輸出集合前3條文檔;
-
將文檔按照學(xué)習(xí)人數(shù) learning_num 升序排序;
-
輸出除了前兩條以外的文檔。
> use test2
switched to db test2
> db.educoder.insert({_id:1,course:'Python表達(dá)式問題求解實(shí)訓(xùn)',author:'李暾',tags:['Python基礎(chǔ)','求解'],learning_num:1882})
WriteResult({ "nInserted" : 1 })
> db.educoder.insert({_id:2,course:'Java語言之基本語法',author:'余躍',tags:['Java基礎(chǔ)','語法'],learning_num:814})
WriteResult({ "nInserted" : 1 })
> db.educoder.insert({_id:3,course:'Python面向?qū)ο缶幊虒?shí)訓(xùn)',author:'李暾',tags:['Python基礎(chǔ)','面向?qū)ο?],learning_num:143})
WriteResult({ "nInserted" : 1 })
> db.educoder.insert({_id:4,course:'Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)',author:'prophet5',tags:['Android','物聯(lián)網(wǎng)','移動(dòng)開發(fā)'],learning_num:207})
WriteResult({ "nInserted" : 1 })
> db.educoder.aggregate({$limit:3})
{ "_id" : 1, "course" : "Python表達(dá)式問題求解實(shí)訓(xùn)", "author" : "李暾", "tags" : [ "Python基礎(chǔ)", "求解" ], "learning_num" : 1882 }
{ "_id" : 2, "course" : "Java語言之基本語法", "author" : "余躍", "tags" : [ "Java基礎(chǔ)", "語法" ], "learning_num" : 814 }
{ "_id" : 3, "course" : "Python面向?qū)ο缶幊虒?shí)訓(xùn)", "author" : "李暾", "tags" : [ "Python基礎(chǔ)", "面向?qū)ο? ], "learning_num" : 143 }
> db.educoder.aggregate({$sort:{learning_num:1}})
{ "_id" : 3, "course" : "Python面向?qū)ο缶幊虒?shí)訓(xùn)", "author" : "李暾", "tags" : [ "Python基礎(chǔ)", "面向?qū)ο? ], "learning_num" : 143 }
{ "_id" : 4, "course" : "Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)", "author" : "prophet5", "tags" : [ "Android", "物聯(lián)網(wǎng)", "移動(dòng)開發(fā)" ], "learning_num" : 207 }
{ "_id" : 2, "course" : "Java語言之基本語法", "author" : "余躍", "tags" : [ "Java基礎(chǔ)", "語法" ], "learning_num" : 814 }
{ "_id" : 1, "course" : "Python表達(dá)式問題求解實(shí)訓(xùn)", "author" : "李暾", "tags" : [ "Python基礎(chǔ)", "求解" ], "learning_num" : 1882 }
> db.educoder.aggregate({$skip:2})
{ "_id" : 3, "course" : "Python面向?qū)ο缶幊虒?shí)訓(xùn)", "author" : "李暾", "tags" : [ "Python基礎(chǔ)", "面向?qū)ο? ], "learning_num" : 143 }
{ "_id" : 4, "course" : "Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)", "author" : "prophet5", "tags" : [ "Android", "物聯(lián)網(wǎng)", "移動(dòng)開發(fā)" ], "learning_num" : 207 }
第3關(guān):2-2-3聚合表達(dá)式對(duì)文檔數(shù)據(jù)進(jìn)行統(tǒng)計(jì)
一、本關(guān)任務(wù):按照編程要求,使用aggregate()
方法,結(jié)合聚合管道操作符和聚合表達(dá)式對(duì)文檔數(shù)據(jù)進(jìn)行統(tǒng)計(jì)。
二、相關(guān)知識(shí)
為了完成本關(guān)任務(wù),你需要掌握:
1.常用聚合表達(dá)式; 2.如何結(jié)合聚合管道操作符使用聚合表達(dá)式完成統(tǒng)計(jì)。
聚合表達(dá)式
常用的幾個(gè)聚合表達(dá)式:
表達(dá)式 | 用法 |
---|---|
$sum | 計(jì)算總和 |
$avg | 計(jì)算平均值 |
$min | 獲取集合中所有文檔對(duì)應(yīng)值的最小值 |
$max | 獲取集合中所有文檔對(duì)應(yīng)值的最大值 |
$push | 在結(jié)果文檔中插入值到一個(gè)數(shù)組中 |
$addToSet | 在結(jié)果文檔中插入值到一個(gè)數(shù)組中,但不創(chuàng)建副本 |
$first | 根據(jù)資源文檔的排序獲取第一個(gè)文檔數(shù)據(jù) |
$last | 根據(jù)資源文檔的排序獲取最后一個(gè)文檔數(shù)據(jù) |
如何對(duì)文檔進(jìn)行統(tǒng)計(jì)
例:在數(shù)據(jù)庫mydb2
有集合educoder
內(nèi)容如下:
_id | course | author | tags | learning_num |
---|---|---|---|---|
1 | Python表達(dá)式問題求解實(shí)訓(xùn) | 李暾 | Python基礎(chǔ),求解 | 1882 |
2 | Java語言之基本語法 | 余躍 | Java基礎(chǔ),語法 | 814 |
3 | Python面向?qū)ο缶幊虒?shí)訓(xùn) | 李暾 | Python基礎(chǔ),面向?qū)ο?/td> | 143 |
4 | Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1) | prophet5 | Android,物聯(lián)網(wǎng),移動(dòng)開發(fā) | 207 |
首先插入數(shù)據(jù),見第一關(guān);
-
現(xiàn)在我們通過
aggregate()
方法來獲取每個(gè)作者擁有的實(shí)訓(xùn)數(shù)量,命名為:num_course
:db.educoder.aggregate([{$group:{_id:'$author',num_course:{$sum:1}}}])
命令解析:
-
先通過聚合管道操作符
$group
將author
字段數(shù)據(jù)分組; -
$sum:1
的含義:如果前面的情況出現(xiàn)一次,就加1
,如果后面為$sum:2
,那么前面條件每滿足一次就加2
;
-
通過
aggregate()
方法來獲取每個(gè)作者的實(shí)訓(xùn)學(xué)習(xí)總?cè)藬?shù)learning_sum
:db.educoder.aggregate([{$group:{_id:'$author',learning_sum:{$sum:'$learning_num'}}}])
編程要求
為了減少你的工作量,給出以下文檔內(nèi)容:
{
_id:1,
course:'Python表達(dá)式問題求解實(shí)訓(xùn)',
author:'李暾',
tags:['Python基礎(chǔ)','求解'],
learning_num:1882
},
{
_id:2,
course:'Java語言之基本語法',
author:'余躍',
tags:['Java基礎(chǔ)','語法'],
learning_num:814
},
{
_id:3,
course:'Python面向?qū)ο缶幊虒?shí)訓(xùn)',
author:'李暾',
tags:['Python基礎(chǔ)','面向?qū)ο?],
learning_num:143
},
{
_id:4,
course:'Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)',
author:'prophet5',
tags:['Android','物聯(lián)網(wǎng)','移動(dòng)開發(fā)'],
learning_num:207
}
先在命令行中操作,將例子中的文檔插入數(shù)據(jù)庫test3
中的集合educoder
中,然后仿照例子中的查詢方法,再在右側(cè)代碼欄Begin-End
中按要求輸入符合以下3
條要求的命令,以分號(hào);
隔開(由于測(cè)試需要,請(qǐng)?jiān)诖a里$
符號(hào)前添加轉(zhuǎn)義符\
,不需要有空格,格式如:\$
,平時(shí)在命令行操作不需要):
-
將文檔按照作者
author
分組,然后取得每個(gè)組的第一個(gè)實(shí)訓(xùn)名first_course
; -
查詢跟隨每個(gè)作者
author
的平均學(xué)習(xí)人數(shù)learning_avg
; -
統(tǒng)計(jì)集合中各
tags
擁有的課程數(shù)量course_num
(提示:先將tags
字段使用$unwind
拆分再統(tǒng)計(jì))。
具體的返回結(jié)果,請(qǐng)查看測(cè)試集。
> use test3
switched to db test3
> db.educoder.insert([
{_id:1,course:'Python表達(dá)式問題求解實(shí)訓(xùn)',author:'李暾',tags:['Python基礎(chǔ)','求解'],learning_num:1882},
{_id:2,course:'Java語言之基本語法',author:'余躍',tags:['Java基礎(chǔ)','語法'],learning_num:814},
{_id:3,course:'Python面向?qū)ο缶幊虒?shí)訓(xùn)',author:'李暾',tags:['Python基礎(chǔ)','面向?qū)ο?],learning_num:143},
{_id:4,course:'Android綜合實(shí)訓(xùn)之物聯(lián)網(wǎng)移動(dòng)應(yīng)用開發(fā)(1)',author:'prophet5',tags:['Android','物聯(lián)網(wǎng)','移動(dòng)開發(fā)'],learning_num:207}])
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 4,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
文章來源地址http://www.zghlxwxcb.cn/news/detail-486606.html
到了這里,關(guān)于分布式數(shù)據(jù)庫NoSQL(四)——MongoDB 之聚合函數(shù)查詢統(tǒng)計(jì)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!