一、簡介
創(chuàng)新互聯(lián)主營范縣網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都app軟件開發(fā),范縣h5成都微信小程序搭建,范縣網(wǎng)站營銷推廣歡迎范縣等地區(qū)企業(yè)咨詢
MongoDB的聚合框架,主要用來對集合中的文檔進(jìn)行變換和組合,從而對數(shù)據(jù)進(jìn)行分析以加以利用。
聚合框架的基本思路是:
采用多個(gè)構(gòu)件來創(chuàng)建一個(gè)管道,用于對一連串的文檔進(jìn)行處理。
這些構(gòu)件包括:
篩選(filtering)、投影(projecting)、分組(grouping)、排序(sorting)、限制(limiting)和跳過(skipping)。
使用聚合框架的方式:
db.集合.aggregate(構(gòu)件1,構(gòu)件2…)
注意:由于聚合的結(jié)果要返回到客戶端,因此聚合結(jié)果必須限制在16M以內(nèi),這是MongoDB支持的最大響應(yīng)消息的大小。
二、使用例子
2.1、準(zhǔn)備樣例數(shù)據(jù)
for(var i=0;i<100;i++){ for(var j=0;j<4;j++){ db.scores.insert({"studentId":"s"+i,"course":"課程"+j,"score":Math.random()*100}); } }
2.2、找出考80分以上的課程門數(shù)最多的3個(gè)學(xué)生
步驟:
1:找到所有考了80分以上的學(xué)生,不區(qū)分課程
> db.scores.aggregate({"$match":{"score":{$gte:80}}});
2:將每個(gè)學(xué)生的名字投影出來
> db.scores.aggregate({"$match":{"score":{$gte:80}}},{$project:{"studentId":1}});
3:對學(xué)生的名字排序,某個(gè)學(xué)生的名字出現(xiàn)一次,就給他加1
> db.scores.aggregate({"$match":{"score":{$gte:80}}},{$project:{"studentId":1}},{$group:{"_id":"$studentId","count":{$sum:1}}});
4:對結(jié)果集按照count進(jìn)行降序排列
> db.scores.aggregate({"$match":{"score":{$gte:80}}},{$project:{"studentId":1}},{$group:{"_id":"$studentId","count":{$sum:1}}},{"$sort":{"count":-1}});
5:返回前面的3條數(shù)據(jù)
db.scores.aggregate({"$match":{"score":{$gte:80}}},{$project:{"studentId":1}},{$group:{"_id":"$studentId","count":{$sum:1}}},{"$sort":{"count":-1}},{"$limit":3});
三、管道操作符
每個(gè)操作符接受一系列的文檔,對這些文檔做相應(yīng)的處理,然后把轉(zhuǎn)換后的文檔作為結(jié)果傳遞給下一個(gè)操作符。最后一個(gè)操作符會(huì)將結(jié)果返回。
不同的管道操作符,可以按照任意順序,任意個(gè)數(shù)組合在一起使用。
3.1、篩選命令$match
用于對文檔集合進(jìn)行篩選,里面可以使用所有常規(guī)的查詢操作符。通常會(huì)放置在管道最前面的位置,理由如下:
1:快速將不需要的文檔過濾,減少后續(xù)操作的數(shù)據(jù)量
2:在投影和分組之前做篩選,查詢可以使用索引
3.2、投影命令$project
用來從文檔中提取字段,可以指定包含和排除字段,也可以重命名字段。比如要將studentId改為sid,如下:
db.scores.aggregate({"$project":{"sid":"$studentId"}})
管道操作符還可以使用表達(dá)式,以滿足更復(fù)雜的需求。
管道操作符$project的數(shù)學(xué)表達(dá)式:
比如給成績集體加20分,如下:
> db.scores.aggregate({"$project":{"studentId":1,"newScore":{$add:["$score",20]}}});
支持的操作符和相應(yīng)語法:
1:$add : [expr1[,expr2,…exprn]]
2:$subtract:[expr1,expr2]
3:$multiply:[expr1[,expr2,…exprn]]
4:$divice:[expr1,expr2]
5:$mod:[expr1,expr2]
管道操作符$project的日期表達(dá)式:
聚合框架包含了一些用于提取日期信息的表達(dá)式,如下:
$year、$month、$week、$dayOfMonth、$dayOfWeek、$dayOfYear、$hour、$minute、$second 。
注意:這些只能操作日期型的字段,不能操作數(shù)據(jù),使用示例:
{"$project":{"opeDay":{"$dayOfMonth":"$recoredTime"}}}
管道操作符$project的字符串表達(dá)式:
1:$substr : [expr,開始位置,要取的字節(jié)個(gè)數(shù)]
2:$concat:[expr1[,expr2,…exprn]]
3:$toLower:expr
4:$toUpper:expr
例如:{"$project":{"sid":{$concat:["$studentId","cc"]}}}
管道操作符$project的邏輯表達(dá)式:
1:$cmp:[expr1,expr2] :比較兩個(gè)表達(dá)式,0表示相等,正數(shù)前面的大,負(fù)數(shù)后面的大
2:$strcasecmp:[string1,string2] :比較兩個(gè)字符串,區(qū)分大小寫,只對由羅馬字符組成的字符串有效
3:$eq、$ne、$gt、$gte、$lt、$lte :[expr1,expr2]
4:$and、$or、$not
5:$cond:[booleanExpr,trueExpr,falseExpr]:如果boolean表達(dá)式為true,返回true表達(dá)式,否則返回false表達(dá)式
6:$ifNull:[expr,otherExpr]:如果expr為null,返回otherExpr,否則返回expr
例如:db.scores.aggregate({"$project":{"newScore":{$cmp:["$studentId","sss"]}}})
3.3、分組命令$group
用來將文檔依據(jù)特定字段的不同值進(jìn)行分組。選定了分組字段過后,就可以把這些字段傳遞給$group函數(shù)的“_id”字段了。例如:
db.scores.aggregate({“$group”:{“_id”:“$studentId”}});
或者是
db.scores.aggregate({"$group":{"_id":{"sid":"$studentId","score":"$score"}}});
$group支持的操作符:
1:$sum:value :對于每個(gè)文檔,將value與計(jì)算結(jié)果相加
2:$avg:value :返回每個(gè)分組的平均值
3:$max:expr :返回分組內(nèi)的最大值
4:$min:expr :返回分組內(nèi)的最小值
5:$first:expr :返回分組的第一個(gè)值,忽略其他的值,一般只有排序后,明確知道數(shù)據(jù)順序的時(shí)候,這個(gè)操作才有意義
6:$last:expr :與上面一個(gè)相反,返回分組的最后一個(gè)值
7:$addToSet:expr :如果當(dāng)前數(shù)組中不包含expr,那就將它加入到數(shù)組中
8:$push:expr:把expr加入到數(shù)組中
3.4、拆分命令$unwind
用來把數(shù)組中的每個(gè)值拆分成為單獨(dú)的文檔。
3.5、排序命令$sort
可以根據(jù)任何字段進(jìn)行排序,與普通查詢中的語法相同。如果要對大量的文檔進(jìn)行排序,強(qiáng)烈建議在管道的第一個(gè)階段進(jìn)行排序,這時(shí)可以使用索引。
3.6、常見的聚合函數(shù)
1:count:用于返回集合中文檔的數(shù)量
2:distinct:找出給定鍵的所有不同值,使用時(shí)必須指定集合和鍵,例如:
db.runCommand({"distinct":"users","key":"userId"});
四、MapReduce
在MongoDB的聚合框架中,還可以使用MapReduce,它非常強(qiáng)大和靈活,但具有一定的復(fù)雜性,專門用于實(shí)現(xiàn)一些復(fù)雜的聚合功能。
MongoDB中的MapReduce使用JavaScript來作為查詢語言,因此能表達(dá)任意的邏輯,但是它運(yùn)行非常慢,不應(yīng)該用在實(shí)時(shí)的數(shù)據(jù)分析中。
4.1、MapReduce的HelloWorld
實(shí)現(xiàn)的功能,找出集合中所有的鍵,并統(tǒng)計(jì)每個(gè)鍵出現(xiàn)的次數(shù)。
1:Map函數(shù)使用emit函數(shù)來返回要處理的值,示例如下:
var map = function(){ for(var key in this){ emit(key,{count:1}); } }
this表示對當(dāng)前文檔的引用。
2:reduce函數(shù)需要處理Map階段或者是前一個(gè)reduce的數(shù)據(jù),因此reduce返回的文檔必須要能作為reduce的第二個(gè)參數(shù)的一個(gè)元素,示例如下:
var reduce = function(key,emits){ var total = 0; for(var i in emits){ total += emits[i].count; } return {"count":total}; };
3:運(yùn)行MapReduce,示例如下:
> var mr =db.runCommand({"mapreduce":"scores","map":map,"reduce":reduce,"out":"mrout"});
說明:scores是集合名,map是map函數(shù),reduce是reduce函數(shù),mrout是輸出的變量名
4:查詢最終的結(jié)果,示例如下:
db.mrout.find();
還可以改變一下,比如統(tǒng)計(jì)studentId中值,以及每個(gè)值出現(xiàn)的次數(shù),就可以如下操作:
1:修改map函數(shù),示例如下:
var map = function(){ emit(this.studentId,{count:1}); };
2:reduce函數(shù)不用改
3:重新執(zhí)行
db.runCommand({"mapreduce":"scores","map":map,"reduce":reduce,"out":"mrout"});
4:查看最終結(jié)果
db.mrout.find();
4.2、更多MapReduce可選的鍵
1:finalize:function :可以將reduce的結(jié)果發(fā)送到finalize,這是整個(gè)處理的最后一步
2:keeptemp:boolean :是否在連接關(guān)閉的時(shí)候,保存臨時(shí)結(jié)果集合
3:query:document :在發(fā)送給map前對文檔進(jìn)行過濾
4:sort:document :在發(fā)送給map前對文檔進(jìn)行排序
5:limit:integer :發(fā)往map函數(shù)的文檔數(shù)量上限
6:scope:document :可以在javascript中使用的變量
7:verbose:boolean :是否記錄詳細(xì)的 五、聚合命令group 用來對集合進(jìn)行分組,分組過后,再對每一個(gè)分組內(nèi)的文檔進(jìn)行聚合。 比如要對studentId進(jìn)行分組,找到每個(gè)學(xué)生最高的分?jǐn)?shù),可以如下步驟進(jìn)行: ns:指定要分組的集合 key:指定分組的鍵 initial:每一組的reduce函數(shù)調(diào)用的時(shí)候,在開頭的時(shí)候調(diào)用一次,以做初始化 $reduce:在每組中的每個(gè)文檔上執(zhí)行,系統(tǒng)會(huì)自動(dòng)傳入兩個(gè)參數(shù),doc是當(dāng)前處理的文檔,prev是本組前一次執(zhí)行的結(jié)果文檔 你還可以在group的時(shí)候添加條件,就是加入condition,示例如: 同樣可以使用finalizer來對reduce的結(jié)果進(jìn)行最后的處理,比如要求每個(gè)學(xué)生的平均分,就可以先按照studentId分組,求出一個(gè)總的分?jǐn)?shù)來,然后在finalizer里面,求平均分: 注意:finalize是只在每組結(jié)果返回給用戶前調(diào)用一次,也就是每組結(jié)果只調(diào)用一次 對于分組的key較為復(fù)雜的時(shí)候,還可以采用函數(shù)來做為鍵,比如讓鍵不區(qū)分大小下,就可以如下定義: 注意:要使用$keyf來定義函數(shù)作為鍵,另外一定要返回對象的格式
新聞標(biāo)題:MongoDB(4):聚合框架
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、、動(dòng)態(tài)網(wǎng)站、響應(yīng)式網(wǎng)站、微信小程序、虛擬主機(jī)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源:
創(chuàng)新互聯(lián)
db.runCommand({"group":{
"ns":"scores",
"key":{"studentId":1},
"initial":{"score":0},
"$reduce":function(doc,prev){
if(doc.score > prev.score){
prev.score = doc.score;
}
}
}});
db.runCommand({"group":{
"ns":"scores",
"key":{"studentId":1},
"initial":{"score":0},
"$reduce":function(doc,prev){
if(doc.score > prev.score){
prev.score = doc.score;
}
}
,"condition":{"studentId":{$lt:"s2"}}
}});
db.runCommand({"group":{
"ns":"scores",
"key":{"studentId":1},
"initial":{"total":0},
"$reduce":function(doc,prev){
prev.total += doc.score;
},
"condition":{"studentId":{"$lt":"s2"}},
"finalize":function(prev){
prev.avg = prev.total/3;
}
}});
db.runCommand({"group":{
"ns":"scores",
$keyf:function(doc){
return {studentId:doc.studentId.toLowerCase()};
},
"initial":{"total":0},
"$reduce":function(doc,prev){
prev.total += doc.score;
},
"condition":{"$or":[{"studentId":{"$lt":"s2"}},{"studentId":"S0"}]},
"finalize":function(prev){
prev.avg = prev.total/3;
}
}});
當(dāng)前URL:http://sd-ha.com/article8/popjop.html