MongoDB
中主要有三個(gè)函數(shù):
-
group
:分組統(tǒng)計(jì) -
aggregate
:簡(jiǎn)單聚合 -
mapReduce
:強(qiáng)大統(tǒng)計(jì)
1 group
1.1 定義
MongoDB
中使用group
來(lái)進(jìn)行分組聚合畔勤,語(yǔ)法如下:
db.collection.group(document);
document中信息:
{
key:{key1:true,key2:true},
cond:{},
reduce:function(curr,result){},
initial:{},
finalize:function(curr,result){}
}
document中字段說(shuō)明:
-
key
:分組字段腿倚,作為分組的key,等價(jià)于sql中g(shù)roup by a,b -
cond
:查詢條件 -
reduce
:聚合函數(shù)
一個(gè)聚合函數(shù)操作文檔的分組操作期間胚想。這些函數(shù)可以返回一個(gè)sum或count。
該函數(shù)接受兩個(gè)參數(shù):當(dāng)前文檔
和這個(gè)群體聚集的結(jié)果文檔
-
initial
:初始化聚合結(jié)果文檔變量霸饲,為空時(shí)自動(dòng)為每列提供初始變量 -
finalize
:統(tǒng)計(jì)一組后的回調(diào)函數(shù)
在db.collection.group()
返回最終結(jié)果之前,此功能可以修改的結(jié)果文檔或替換的結(jié)果文檔作為一個(gè)整體
注意
:
-
group
需要我們手寫(xiě)聚合函數(shù)的業(yè)務(wù)邏輯 -
group
不支持shard cluster
之众,無(wú)法分布式運(yùn)算 - 有些版本不支持
group
函數(shù)则奥,可以通過(guò)db.collection.help()
函數(shù)查看
1.2 操作group
1.2.1 求數(shù)目
db.collection.group({
key:{cat_id:1},
cond:{},
reduce:function(curr,result) {
result.cnt += 1;
},
initial:{cnt:0}
})
類似于sql:
select count(*) from goods group by cat_id;
1.2.2 求總和
db.collection.group({
key:{cat_id:1},
cond:{},
reduce:function(curr,result) {
result.num += curr.goods_number;
},
initial:{num:0}
})
類似于sql:
select sum(goods_number) from goods group by cat_id;
1.2.3 求最大
db.collection.group({
key:{cat_id:1},
cond:{},
reduce:function(curr , result) {
if(curr.shop_price > result.max) {
result.max = curr.shop_price;
}
},
initial:{max:0}
})
類似于sql:
select max(shop_price) from goods group by cat_id;
1.2.4 求平均
求平均時(shí)主要用到了finalize
函數(shù)
db.collection.group({
key:{cat_id:1},
cond:{},
reduce:function(curr , result) {
result.cnt += 1; //統(tǒng)計(jì)數(shù)量
result.sum += curr.shop_price; //統(tǒng)計(jì)總量
},
initial:{sum:0,cnt:0},
finalize:function(result) {
result.avg = result.sum/result.cnt;//求平均
}
})
2 aggregate
2.1 定義
MongoDB
中聚合(aggregate
)主要用于處理數(shù)據(jù)(諸如統(tǒng)計(jì)平均值,求和等)拥坛,并返回計(jì)算后的數(shù)據(jù)結(jié)果
基本語(yǔ)法:
db.collection.aggregate(docment);
具體方法實(shí)例有:$match蓬蝶,$project,$group猜惋,$unwind丸氛,$sort,$limit著摔,$skip
等相關(guān)操作
2.2 操作aggregate
準(zhǔn)備腳本
> db.book.insertMany([
{"_id": 1, "author": "monday", "book": "《Java》", "like": 10},
{"_id": 2, "author": "monday", "book": "《Java Core》", "like": 20},
{"_id": 3, "author": "mengday", "book": "《Spring Boot》", "like": 15}
])
> db.book.find()
{ "_id" : 1, "author" : "monday", "book" : "《Java》", "like" : 10 }
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20 }
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15 }
2.2.1 $match篩選
用于過(guò)濾數(shù)據(jù)缓窜,只輸出符合條件的文檔。$match
使用MongoDB
的標(biāo)準(zhǔn)查詢操作谍咆。
篩選條件禾锤,相當(dāng)于SQL
中的where
部分,過(guò)濾掉不滿足條件的文檔,可以使用常規(guī)的查詢操作符卧波,如 $gt
时肿、$lt
、$in
等港粱。
> db.book.aggregate({"$match": {"like": {"$gt": 10}}})
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20 }
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15 }
當(dāng)match
在group
之前類似于SQL
的where
操作,在group
之后類似于SQL
的having
操作
db.book.aggregate([{"$match": {"like": {"$gte": 10}}},{$group:{_id:'$author',total:{$sum:1}}},{$match:{total:{$gte:2}}}])
{ "_id": "monday", "total": 2}
2.2.2 $project映射
$project
:修改輸入文檔的結(jié)構(gòu)〔槠海可以用來(lái)重命名寸宏、增加或刪除域,也可以用于創(chuàng)建計(jì)算結(jié)果以及嵌套文檔偿曙。
映射相當(dāng)于SQL中的 select 映射 from
之間的部分氮凝,用于指定要查詢的字段,或者對(duì)字段進(jìn)行一些處理望忆。
投射常用的3個(gè)功能:
- 對(duì)字段重命名罩阵。
- 在投射中使用一些表達(dá)式對(duì)字段值進(jìn)行處理:數(shù)學(xué)表達(dá)式、日期表達(dá)式启摄、字符串表達(dá)式稿壁、邏輯表達(dá)式(比較表達(dá)式、布爾表達(dá)式歉备、控制語(yǔ)句)傅是。
- 用于包含、排除字段: 設(shè)置要查詢或者要過(guò)濾掉的字段蕾羊,
- 0: 要過(guò)濾掉的字段喧笔,不顯示
- 1:需要查詢的字段。
2.2.2.1 自定義字段
查詢自定義的字段
db.book.aggregate({"$project": {"_id": 0, "book": 1, "like": 1}})
{ "book" : "《Java》", "like" : 10 }
{ "book" : "《Java Core》", "like" : 20 }
{ "book" : "《Spring Boot》", "like" : 15 }
2.2.2.2 起別名
對(duì)字段起別名龟再,相當(dāng)于SQL中的as的作用
db.book.aggregate({"$project": {"_id": 0, "book name": "$book", "like": 1}})
{ "like" : 10, "book name" : "《Java》" }
{ "like" : 20, "book name" : "《Java Core》" }
{ "like" : 15, "book name" : "《Spring Boot》" }
2.2.2.3 引用原字段:$字段名
如果對(duì)_id進(jìn)行起別名會(huì)將別名作為一個(gè)新的字段加入到文檔中书闸,而_id保持不變
db.book.aggregate({"$project": {"id": "$_id", "book name": "$book", "like": 1}})
{ "_id" : 1, "like" : 10, "id" : 1, "book name" : "《Java》" }
{ "_id" : 2, "like" : 20, "id" : 2, "book name" : "《Java Core》" }
{ "_id" : 3, "like" : 15, "id" : 3, "book name" : "《Spring Boot》" }
2.2.2.4 使用算術(shù)表達(dá)式
使用算術(shù)表達(dá)式 $add
、$subtract
利凑、$multiply
梗劫、$divide
、$mod
處理數(shù)字類型的字段
db.book.aggregate({"$project": {"like": {"$add": ["$like", "$like", 1]}}})
{ "_id" : 1, "like" : 21 }
{ "_id" : 2, "like" : 41 }
{ "_id" : 3, "like" : 31 }
2.2.2.5 字符串截取
$substrCP: [exp, startOffset, numToReturn] : 字符串截取操作
db.book.aggregate({"$project": {"newValue": {"$substrCP": ["$book", 1, 4]}}})
{ "_id" : 1, "newValue" : "Java" }
{ "_id" : 2, "newValue" : "Java" }
{ "_id" : 3, "newValue" : "Spri" }
2.2.2.6 字符串拼接
$concat:[exp1, exp2, ..., expN]: 字符串操作:將數(shù)組中的多個(gè)元素拼接在一起
db.book.aggregate({"$project": {"newValue": {"$concat": ["$book", "(", "$author", ")"]}}})
{ "_id" : 1, "newValue" : "《Java》(monday)" }
{ "_id" : 2, "newValue" : "《Java Core》(monday)" }
{ "_id" : 3, "newValue" : "《Spring Boot》(mengday)" }
2.2.2.7 大小寫(xiě)轉(zhuǎn)換
$toUpper
: 字符串操作截碴,轉(zhuǎn)大寫(xiě)
$toLower
: exp, 字符串轉(zhuǎn)小寫(xiě)
db.book.aggregate({"$project": {"newValue": {"$toUpper": "$book"}}})
{ "_id" : 1, "newValue" : "《JAVA》" }
{ "_id" : 2, "newValue" : "《JAVA CORE》" }
{ "_id" : 3, "newValue" : "《SPRING BOOT》" }
2.2.2.8 日期表達(dá)式
日期表達(dá)式:用于獲取日期中的任意一部分梳侨,年月日時(shí)分秒 星期等
$year
、$month
日丹、$dayOfMonth
走哺、$dayOfWeek
、$dayOfYear
哲虾、$hour
丙躏、$minute
、$second
-
$dayOfYear
: 返回該日期是這一年的第幾天(全年 366 天)束凑。 -
$dayOfMonth
: 返回該日期是這一個(gè)月的第幾天(1到31)晒旅。 -
$dayOfWeek
: 返回的是這個(gè)周的星期幾(1:星期日,7:星期六)汪诉。 -
$year
: 返回該日期的年份部分废恋。 -
$month
: 返回該日期的月份部分( 1 到 12)谈秫。 -
$week
: 返回該日期是所在年的第幾個(gè)星期( 0 到 53)。 -
$hour
: 返回該日期的小時(shí)部分鱼鼓。 -
$minute
: 返回該日期的分鐘部分拟烫。 -
$second
: 返回該日期的秒部分(以0到59之間的數(shù)字形式返回日期的第二部分,但可以是60來(lái)計(jì)算閏秒)迄本。 -
$millisecond
:返回該日期的毫秒部分( 0 到 999)硕淑。 -
$dateToString
: { $dateToString: { format: , date: } }。
準(zhǔn)備腳本
db.book.find()
{ "_id" : 1, "author" : "monday", "book" : "《Java》", "like" : 10, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }
求日期
db.book.aggregate({"$project": {"year": {"$year": "$publishDate"}}})
{ "_id" : 1, "year" : 2021 }
{ "_id" : 2, "year" : 2021 }
{ "_id" : 3, "year" : 2021 }
2.2.2.9 比較非字符串大小
$cmp: [exp1, exp2]
: 用于比較兩個(gè)非字符串類型的值嘉赎,exp1 == exp2 返回 0置媳, 小于返回一個(gè)負(fù)數(shù),大于返回一個(gè)正數(shù)
db.book.aggregate({"$project": {"result": {"$cmp": ["$like", 15]}}})
{ "_id" : 1, "result" : -1 }
{ "_id" : 2, "result" : 1 }
{ "_id" : 3, "result" : 0 }
2.2.2.10 比較字符串大小
$strcasecmp
: 用于比較字符串, 不區(qū)分大小寫(xiě)公条,相等返回0
db.book.aggregate({"$project": {"result": {"$strcasecmp": ["$author", "Monday"]}}})
{ "_id" : 1, "result" : 0 }
{ "_id" : 2, "result" : 0 }
{ "_id" : 3, "result" : -1 }
2.2.2.11 比較表達(dá)式
$eq
: 用于判斷兩個(gè)表達(dá)式是否相等拇囊,相等返回true,不相等返回false, 區(qū)分大小寫(xiě)
$ne
: 不相等
$gt
: 大于
$gte
: 大于等于
$lt
: 小于
$lte
: 小于等于
注意:{"$eq": ["$author", "monday"]}
中$eq
鍵的值是個(gè)數(shù)組而不是一個(gè)對(duì)象
db.book.aggregate({"$project": {"result": {"$eq": ["$author", "monday"]}}})
{ "_id" : 1, "result" : true }
{ "_id" : 2, "result" : true }
{ "_id" : 3, "result" : false }
2.2.2.12 And連接
$and:[exp1, exp2, ..., expN]
用于連接多個(gè)條件赃份,當(dāng)所有條件為真的時(shí)候?yàn)?code>true
db.book.aggregate({"$project": {"result": {"$and": [{"$eq": ["$author", "monday"]}, {"$gt": ["$_id", 1]}]}}})
{ "_id" : 1, "result" : false }
{ "_id" : 2, "result" : true }
{ "_id" : 3, "result" : false }
2.2.2.13 Or連接
$or: [exp1, exp2, ..., expN]
有一個(gè)為真則為真
db.book.aggregate({"$project": {"result": {"$or": [{"$eq": ["$author", "monday"]}, {"$eq": ["$_id", 1]}]}}})
{ "_id" : 1, "result" : true }
{ "_id" : 2, "result" : true }
{ "_id" : 3, "result" : false }
2.2.2.14 not連接
$not: exp
用于取反操作
db.book.aggregate({"$project": {"result": {"$not": {"$eq": ["$author", "monday"]}}}})
{ "_id" : 1, "result" : false }
{ "_id" : 2, "result" : false }
{ "_id" : 3, "result" : true }
2.2.2.15 三位運(yùn)算符
$cond: [booleanExp, trueExp, falseExp]
: 三位運(yùn)算符
db.book.aggregate({"$project": {"result": {"$cond": [ {"$eq": ["$author", "monday"]}, "M", "F" ]}}})
{ "_id" : 1, "result" : "M" }
{ "_id" : 2, "result" : "M" }
{ "_id" : 3, "result" : "F" }
2.2.2.16 ifNull連接
$ifNull: [expr, replacementExpr]
: 如果字段不存在或者字段值為null
會(huì)返回replacementExpr
寂拆,否則返回原來(lái)的值,即字段為空時(shí)給一個(gè)默認(rèn)值
IFNULL(bool, default_value)
db.book.aggregate({"$project": {"result": {"$ifNull": ["$price", "0.00"]}}})
{ "_id" : 1, "result" : 66 }
{ "_id" : 2, "result" : "0.00" }
{ "_id" : 3, "result" : "0.00" }
2.2.3 $group 分組
2.2.3.1 單字段分組
相當(dāng)于SQL中的group by
部分
$group
表示分組
_id
: 用于指定要分組的字段
count
: 是聚合后的結(jié)果的字段別名抓韩,類似于SQL中的as后面的別名纠永,可以任意定義,字段前面使用$
表示應(yīng)用某個(gè)字段而不是一個(gè)普通的字符串
$sum
: 對(duì)分組中的每個(gè)文檔做什么類型的聚合谒拴,是求和還是求平均數(shù)等尝江,1
:表示對(duì)分組的每一條文檔都加1進(jìn)行統(tǒng)計(jì),這就相當(dāng)于SQL
中的count(*)
select _id, count(*) from book group by author
db.book.aggregate({"$group": {"_id": "$author", "count": {"$sum": 1}}})
{ "_id" : "monday", "count" : 2 }
{ "_id" : "mengday", "count" : 1 }
2.2.3.2 對(duì)多個(gè)字段進(jìn)行分組
類似于:select _id, count(*) from book group by author, like
db.book.aggregate({"$group": {"_id": {"author": "$author", "like": "$like"}, "count": {"$sum": 1}}})
{ "_id" : { "author" : "monday", "like" : 10 }, "count" : 1 }
{ "_id" : { "author" : "monday", "like" : 20 }, "count" : 1 }
{ "_id" : { "author" : "mengday", "like" : 15 }, "count" : 1 }
2.2.3.3 聚合運(yùn)算
$avg
: 求分組中某個(gè)字段的平均值
$max
: 求分組中某個(gè)字段的最大值
$min
: 求分組中某個(gè)字段最小的值
$first
: 求分組中的第一個(gè)值
$last
: 求分組中最后一個(gè)值
db.book.aggregate( {"$group": {"_id": "$author", "avg": {"$avg": "$like"}}} )
{ "_id" : "monday", "avg" : 15 }
{ "_id" : "mengday", "avg" : 15 }
2.2.3.4 addToSet
$addToSet
: 字段引用, 將分組后的每個(gè)文檔指定的值放在set集合中英上,集合不重復(fù)炭序,無(wú)序
db.book.aggregate( {"$group": {"_id": "$author", "likes": {"$addToSet": "$like"}}} )
{ "_id" : "monday", "likes" : [ 20, 10 ] }
{ "_id" : "mengday", "likes" : [ 15 ] }
2.2.3.5 push操作
$push: exp
, 將分組后的每個(gè)文檔指定的值放在數(shù)組中,允許重復(fù)苍日,有序
db.book.aggregate( {"$group": {"_id": "$author", "likes": {"$push": "$like"}}} )
{ "_id" : "mengday", "likes" : [ 15 ] }
{ "_id" : "monday", "likes" : [ 10, 20 ] }
2.2.4 $unwind
將數(shù)組的每一個(gè)元素都單獨(dú)作為一條文檔進(jìn)行拆分惭聂。
db.comments.insert({"_id": 1, "title": "java", "comment": ["good", "very good"]})
db.comments.find()
{ "_id" : 1, "title" : "java", "comment" : [ "good", "very good" ] }
db.comments.aggregate( {"$unwind": "$comment"} )
{ "_id" : 1, "title" : "java", "comment" : "good" }
{ "_id" : 1, "title" : "java", "comment" : "very good" }
2.2.5 $sort
對(duì)文檔進(jìn)行排序,相當(dāng)于SQL中的order by相恃。
db.book.aggregate( {"$sort": {"_id": -1}} )
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20, "publishDate" : ISODate("2021-04-12T13:38:14.829Z"), "price" : null }
{ "_id" : 1, "author" : "monday", "book" : "《Java》", "like" : 10, "publishDate" : ISODate("2021-04-12T13:38:14.829Z"), "price" : 66 }
2.2.6 $limit
限制返回的條數(shù)辜纲,相當(dāng)于SQL中的limit count
語(yǔ)句。
db.book.aggregate( {"$limit": 2} )
{ "_id" : 1, "author" : "monday", "book" : "《Java》", "like" : 10, "publishDate" : ISODate("2021-04-12T13:38:14.829Z"), "price" : 66 }
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20, "publishDate" : ISODate("2021-04-12T13:38:14.829Z"), "price" : null }
2.2.7 $skip
跳過(guò)前N條文檔拦耐,和limit結(jié)合可用于分頁(yè)耕腾。
db.book.aggregate( {"$skip": 2}, {"$limit": 2} )
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }
2.2.8 綜合使用
聚合框架,就是將上一個(gè)操作符處理的結(jié)果交個(gè)下一個(gè)操作符繼續(xù)處理(這就是Linux中的管道操作)杀糯,可以使用任意多個(gè)操作符扫俺,同一個(gè)操作符也可以使用多次
- 首先通過(guò)
$match
過(guò)濾掉不匹配的文檔, - 接著講滿足條件的文檔交給
$group
進(jìn)行分組固翰, - 分組后將將分組后的結(jié)果交給
$sort
進(jìn)行排序狼纬, - 然后將排序后的結(jié)果交給
$skip
處理羹呵,跳過(guò)前幾條, - 把剩下的文檔交給
$limit
處理畸颅,獲取最終的聚合結(jié)果担巩。
db.book.aggregate(
{"$match": {"like": {"$gte" : 10} }},
{"$group": {"_id": "$author", "count": {"$sum": 1}}},
{"$sort": {"count": -1}},
{"$skip": 1},
{"$limit": 1}
)
{ "_id" : "mengday", "count" : 1 }
2.3 常見(jiàn)聚合表達(dá)式
下表展示了一些聚合的計(jì)算表達(dá)式:
表達(dá)式 | 描述 | 實(shí)例 |
---|---|---|
$sum |
計(jì)算總和 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) |
$avg |
計(jì)算平均值 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) |
$min |
獲取集合中所有文檔對(duì)應(yīng)值得最小值 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) |
$max |
獲取集合中所有文檔對(duì)應(yīng)值得最大值方援。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) |
$push |
將值加入一個(gè)數(shù)組中没炒,不會(huì)判斷是否有重復(fù)的值 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) |
$addToSet |
將值加入一個(gè)數(shù)組中,會(huì)判斷是否有重復(fù)的值犯戏,若相同的值在數(shù)組中已經(jīng)存在了送火,則不加入。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first |
根據(jù)資源文檔的排序獲取第一個(gè)文檔數(shù)據(jù)先匪。 | db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) |
$last |
根據(jù)資源文檔的排序獲取最后一個(gè)文檔數(shù)據(jù) | db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) |
3 mapReduce
Map-Reduce
是一種計(jì)算模型种吸,簡(jiǎn)單的說(shuō)就是將大批量的工作(數(shù)據(jù))分解(MAP
)執(zhí)行,然后再將結(jié)果合并成最終結(jié)果(REDUCE
)呀非。
MongoDB
提供的Map-Reduce
非常靈活坚俗,對(duì)于大規(guī)模數(shù)據(jù)分析也相當(dāng)實(shí)用。
3.1 mapReduce語(yǔ)法
以下是MapReduce
的基本語(yǔ)法:
db.collection.mapReduce(
function() {emit(key,value);}, //map 函數(shù)
function(key,values) {return reduceFunction}, //reduce 函數(shù)
{
out: collection,
query: document,
sort: document,
limit: number
}
)
使用 MapReduce
要實(shí)現(xiàn)兩個(gè)函數(shù)Map
函數(shù)和 Reduce
函數(shù),Map
函數(shù)調(diào)用 emit(key, value)
, 遍歷 collection
中所有的記錄, 將 key 與 value 傳遞給 Reduce
函數(shù)進(jìn)行處理岸裙。
Map
函數(shù)必須調(diào)用 emit(key, value)
返回鍵值對(duì)猖败。
參數(shù)說(shuō)明:
-
map
:映射函數(shù) (生成鍵值對(duì)序列,作為reduce
函數(shù)參數(shù))
把屬于同一個(gè)組的數(shù)據(jù),映射到一個(gè)數(shù)組上 -
reduce
:統(tǒng)計(jì)函數(shù)降允,把數(shù)組(同一組)的數(shù)據(jù)恩闻,進(jìn)行運(yùn)算
reduce
函數(shù)的任務(wù)就是將key-values
變成key-value
,也就是把values數(shù)組
變成一個(gè)單一的值value
-
out
:統(tǒng)計(jì)結(jié)果存放集合 (不指定則使用臨時(shí)集合,在客戶端斷開(kāi)后自動(dòng)刪除)剧董。 -
query
:一個(gè)篩選條件幢尚,只有滿足條件的文檔才會(huì)調(diào)用map函數(shù)。(query翅楼。limit尉剩,sort可以隨意組合) -
sort
和limit
結(jié)合的sort
排序參數(shù)(也是在發(fā)往map函數(shù)前給文檔排序),可以優(yōu)化分組機(jī)制 -
limit
發(fā)往map
函數(shù)的文檔數(shù)量的上限(要是沒(méi)有l(wèi)imit毅臊,單獨(dú)使用sort的用處不大)
以下實(shí)例在集合 orders 中查找 status:"A" 的數(shù)據(jù)理茎,并根據(jù) cust_id 來(lái)分組,并計(jì)算 amount 的總和褂微。
3.2 與分組聚合對(duì)比
與Aggregate
中引用集合中字段區(qū)別:
- 在分組聚合
Aggregate
函數(shù)中功蜓,引用原字段用$原字段
- 在
MapReduce
中引用原來(lái)字段用this
,比如:this.age
3.3 使用 mapReduce
準(zhǔn)備腳本
db.user.insertMany([
{"name" : "魯迅","book" : "吶喊","price" : 38.0,"publisher" : "人民文學(xué)出版社"},
{"name" : "曹雪芹","book" : "紅樓夢(mèng)","price" : 22.0,"publisher" : "人民文學(xué)出版社"},
{"name" : "錢鐘書(shū)","book" : "宋詩(shī)選注","price" : 99.0,"publisher" : "人民文學(xué)出版社"},
{"name" : "錢鐘書(shū)","book" : "談藝錄","price" : 66.0,"publisher" : "三聯(lián)書(shū)店"},
{"name" : "魯迅","book" : "彷徨","price" : 55.0,"publisher" : "花城出版社"}
]);
查詢每個(gè)作者的總計(jì)價(jià)格
db.user.mapReduce(
function(){emit(this.name,this.price)},
function(key,value){return Array.sum(value)},
{out:"totalPrice"});
查看處理結(jié)果
db.totalPrice.find();
{
"_id": "魯迅",
"value": 22
}
// 2
{
"_id": "錢鐘書(shū)",
"value": 93
}
// 3
{
"_id": "曹雪芹",
"value": 165
}
或者使用引用的方法(查詢每個(gè)價(jià)格在 40以上的書(shū)宠蚂,并用逗號(hào)分隔)
所有函數(shù)寫(xiě)在一起
db.user.mapReduce(
function(){emit(this.name,this.book)},
function(key,value){return value.join(',')},
{query:{price:{$gt:40}},out:"books"})
db.books.find();
單獨(dú)寫(xiě)式撼,然后引用
var map=function(){emit(this.name,this.book)}
var reduce=function(key,value){return value.join(',')}
var options={query:{price:{$gt:40}},out:"books"}
db.user.mapReduce(map,reduce,options);
3.4 runCommand
3.4.1 語(yǔ)法
db.runCommand(
{
mapReduce: <collection>,
map: <function>,
reduce: <function>,
finalize: <function>,
out: <output>,
query: <document>,
sort: <document>,
limit: <number>,
scope: <document>,
jsMode: <boolean>,
verbose: <boolean>,
bypassDocumentValidation: <boolean>,
collation: <document>
}
)
參數(shù)含義:
-
mapReduce
:表示要操作的集合 -
map
:map函數(shù) -
reduce
:reduce函數(shù) -
finalize
:最終處理函數(shù) -
out
:輸出的集合 -
query
:對(duì)結(jié)果進(jìn)行過(guò)濾 -
sort
:對(duì)結(jié)果排序 -
limit
:返回的結(jié)果數(shù) -
scope
:設(shè)置參數(shù)值,在這里設(shè)置的值在map求厕,reduce著隆,finalize函數(shù)中可見(jiàn) -
jsMode
:是否將地圖執(zhí)行的中間數(shù)據(jù)由javascript對(duì)象轉(zhuǎn)換成BSON對(duì)象扰楼,替換為false -
verbose
:是否顯示詳細(xì)的時(shí)間統(tǒng)計(jì)信息 -
bypassDocumentValidation
:是否繞過(guò)文檔驗(yàn)證 -
collation
:其他一些校對(duì)
3.4.2 案例
如下操作,表示執(zhí)行MapReduce操作重新統(tǒng)計(jì)的集合限制返回條數(shù)美浦,限制返回條數(shù)之后再進(jìn)行統(tǒng)計(jì)操作弦赖,如下:
var map=function(){emit(this.name,this.book)}
var reduce=function(key,value){return value.join(',')}
db.runCommand({mapreduce:'user',map,reduce,out:"books",limit:4,verbose:true})
db.books.find()
執(zhí)行結(jié)果:
{ "_id" : "魯迅", "value" : "吶喊" }
{ "_id" : "曹雪芹", "value" : "紅樓夢(mèng)" }
{ "_id" : "錢鐘書(shū)", "value" : "談藝錄,宋詩(shī)選注" }
這里進(jìn)行對(duì)比發(fā)現(xiàn),因?yàn)閘imit的原因浦辨,魯迅的第一本書(shū)不見(jiàn)了
finalize
操作表示最終處理函數(shù)蹬竖,如下:f1
函數(shù)的第一個(gè)參數(shù)鍵表示emit
中的第一個(gè)參數(shù),第二個(gè)參數(shù)表示reduce
的執(zhí)行結(jié)果流酬,我們可以在f1
中對(duì)這個(gè)結(jié)果進(jìn)行再處理
var f1 = function(key,reduceValue){var obj={};obj.author=key;obj.books=reduceValue; return obj}
var map=function(){emit(this.name,this.book)}
var reduce=function(key,value){return value.join(',')}
db.runCommand({mapreduce:'user',map,reduce,out:"books",finalize:f1})
db.books.find()
執(zhí)行結(jié)果:
{ "_id" : "魯迅", "value" : { "author" : "魯迅", "books" : "彷徨,吶喊" } }
{ "_id" : "曹雪芹", "value" : { "author" : "曹雪芹", "books" : "紅樓夢(mèng)" } }
{ "_id" : "錢鐘書(shū)", "value" : { "author" : "錢鐘書(shū)", "books" : "談藝錄,宋詩(shī)選注" } }