这此之前已经对MongoDB中的一些聚合操作进行了详细的介绍,主要介绍了聚合方法和聚合管道;如果您想对聚合方法和聚合管道进行了解,可以参考:
MongoDB 数据库操作汇总https://blog.csdn.net/m1729339749/article/details/130086022中的聚合操作。
本篇我们介绍另外一种聚合操作(Map-Reduce),其中Map代表的是文档映射,Reduce代表的是对映射的结果进行计算。
一、准备工作
初始化课程成绩数据
db.subjectScores.insertMany([
{ "_id": 1, "name": "张三", "subject": "eng", "score": 80 },
{ "_id": 2, "name": "李四", "subject": "eng", "score": 60 },
{ "_id": 3, "name": "王五", "subject": "eng", "score": 90 },
{ "_id": 4, "name": "张三", "subject": "math", "score": 70 },
{ "_id": 5, "name": "李四", "subject": "math", "score": 90 },
{ "_id": 6, "name": "王五", "subject": "math", "score": 50 },
{ "_id": 7, "name": "张三", "subject": "physics", "score": 80 },
{ "_id": 8, "name": "李四", "subject": "physics", "score": 60 },
{ "_id": 9, "name": "王五", "subject": "physics", "score": 70 }
])
二、Map-Reduce
语法:
db.collection.mapReduce(
<map>,
<reduce>,
{
out: <collection>,
query: <document>,
sort: <document>,
limit: <number>,
finalize: <function>,
scope: <document>,
jsMode: <boolean>,
bypassDocumentValidation: <boolean>
}
)
其中,
<map>:代表的是Map函数(JavaScript函数),它可以把每个输入的文档转换成0个或者多个文档。
map函数的格式如下:
function() {
...
emit(key, value);
}
可以将map函数理解为分组,其中key代表的是分组的字段;value代表的是需要进行聚合运算的字段。
<reduce>:代表的是Reduce函数(JavaScript函数)。
reduce函数的格式如下:
function(key, values) {
...
return result;
}
可以将reduce函数理解为分组后的聚合运算,其中key代表的是分组的字段,values代表的是需要进行聚合运算的字段对应的所有的字段值。
out:代表的是输出结果到集合或者直接输出,如果直接输出使用inline。
输出结果到集合中:
out: { <action>: <collectionName>
[, db: <dbName>] }
<action>:
replace:如果集合存在,则替换现有的集合
merge:如果集合存在,当文档冲突时,则覆盖
reduce:如果集合存在,当文档冲突时,将reduce函数应用于新文档和现有文档(集合中冲突的文档),并将结果覆盖现有文档;
<collectionName>:集合
<dbName>:数据库
直接输出结果:
out: { inline: 1 }
query:代表的是查询选择器,会将满足条件的文档输入到map函数中
如果您想了解查询选择器,可以参考:
MongoDB 查询文档中使用比较选择器、逻辑选择器https://blog.csdn.net/m1729339749/article/details/129965699
MongoDB 查询文档中使用元素选择器、数组选择器https://blog.csdn.net/m1729339749/article/details/129971708
sort:代表的是对输入的文档进行排序,此选项适用于优化
limit:代表的是指定输入到map函数的文档的最大数量
finalize:可选,代表的是对reduce函数输出的文档进行更改,是一个Javascript函数
scope:代表的是定义map、reduce、finalize函数中可以全局使用的变量
jsMode:代表的是在执行map、reduce函数之间,是否将中间数据转换为BSON格式,默认值为false。
(1)如果为false:在内部,MongoDB通过map函数将Javascript对象转换成BSON对象,当调用reduce函数时,BSON对象会被转换成Javascript对象;map-reduce会放置中间BSON对象在临时的磁盘存储中,这将允许对任意大型数据集执行操作。
(2) 如果为true:在内部,map函数执行完之后会保留Javascript对象,在执行reduce函数时不再需要转换,能够更快的得到结果;只能用于映射函数的key少于500000个的情况。
bypassDocumentValidation:可选,是否绕开文档验证
5.0版本以后,Map-Reduce已经过时,建议是使用$accumulator 和 $function 聚合运算符
三、例子:计算学生的总分数
聚合查询如下:
db.subjectScores.mapReduce(
function() {
emit(this.name, this.score);
},
function(key, values) {
return Array.sum(values);
},
{
out: { inline: 1 }
}
)
我们对上面的聚合查询进行解释:
1、map函数中使用name作为key进行分组,score作为value进行聚合运行
2、reduce函数中对values(也就是name相同的所有的score组成的数组)进行求和;这里使用的Array.sum是Javascript函数
3、对mapReduce的结果进行直接输出
聚合查询的结果如下:
{
"results" : [
{
"_id" : "李四",
"value" : 210
},
{
"_id" : "张三",
"value" : 230
},
{
"_id" : "王五",
"value" : 210
}
],
"ok" : 1
}