Map Reduce
一种计算模型,就是将大批量的数据进行分解,再将分解的数据合并成最终需要的结果。
MapReduce不只是MongoDB独有,而是MongoDB也提供这个计算方法,像Java、PHP、Hadoop、Python中都可以使用,适合于处理数据量较大的场景,相较于group和aggtegate来说功能更强大,且更加灵活。
基本用法
>db.collection.mapReduce(
function() {emit(key,value);}, //map 函数
function(key,values) {return reduceFunction}, //reduce 函数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
一个Map Reduce由三部分组成
Map函数
映射函数,必须调用内置的emit
函数,参数key
意为要根据key
来进行分组,参数value
将文档中的字段映射到分组后的数据上(即目标分组需要啥数据放啥数据),此处的this都指向文档。
Reduce函数
统计函数,用于处理需要返回的结果,此处的参数key
和values
对应Map函数中的key
和value
,返回值就是处理的结果。
Options
-
out
指定处理结果输出的集合,必选。 -
query
筛选条件,先查询再进行MapReduce操作。 -
sort
发往Map函数前先给文档排序。 -
limit
发往Map函数的文档数量上限。
实例——Node.js中使用Mongoose实现MapReduce
有如下图所示的articles
文章表,现在需要将每个人的作品汇总到数组里并计算出文章总数输出。
show you code:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/mongo'); // 连接数据库
//连接状态提示
var db_m = mongoose.connection;
db_m.on("error", function (error) {
console.log("数据库连接失败:" + error);
});
db_m.on("open", function () {
console.log("数据库连接成功");
});
// 定义Schema
var Schema = mongoose.Schema;
var articleSchema = new Schema({
name: String,
age: Number,
article: String,
status: String
})
//创建Model
var Article = mongoose.model('Article', articleSchema)
var map = function () { // 定义Map函数
emit(this.name, { // 按名字分组
name: this.name,
articles: this.article,
age: this.age,
artcle_amount: 1,
})
}
var reduce = function (key, values) { // 对应Map函数的参数
var result = {
"articles": [], // 存放文章
"age": "",
"artcle_amount": 0
}
values.forEach(value => {
result.artcle_amount += value.artcle_amount;
result.articles.push(value.articles);
result.age = value.age
});
return result;
}
var options = {
out: "hellos", // 输出的集合名为hello
// query: { // 筛选条件
// status: "disabled"
// }
}
db_m.collection("articles").mapReduce(
map,
reduce,
options
).then(()=>{
console.log("数据处理成功!");
var helloSchema = new Schema({
_id: String,
value: Object
})
//创建Model
var Hello = mongoose.model('Hello', helloSchema)
Hello.find({}, (err, data) => {
if (err) throw err;
console.log(data); // 输出结果
})
})
结果:
/* 1 */
{
"_id" : "dog",
"value" : {
"name" : "dog",
"articles" : "一只单身狗的自我修养",
"age" : 1.0,
"artcle_amount" : 1.0
}
}
/* 2 */
{
"_id" : "john",
"value" : {
"articles" : [
"BUG的艺术",
"BUG传"
],
"age" : 24.0,
"artcle_amount" : 2.0
}
}
/* 3 */
{
"_id" : "zander",
"value" : {
"articles" : [
"BUG记",
"红error梦",
"代码演义",
"代码的弱点"
],
"age" : 23.0,
"artcle_amount" : 4.0
}
}
总结:网上实例真的很少,尤其是在Node.js中实现,完全靠自我摸索,虽然aggrigate也可以实现类似的分组功能,但是灵活性就相差甚远了,而且MapReduce可以实现的功能也不止上述例子,它更占优势的地方在于对大数据的处理速度与灵活性上,更多应用场景还需要多多摸索和实践。