MongoDB映射/减少多个集合?
首先是背景。我以前有一个集合MongoDB映射/减少多个集合?,mongodb,mapreduce,Mongodb,Mapreduce,首先是背景。我以前有一个集合日志,并使用map/reduce生成各种报告。大多数报告都是基于一天内的数据,所以我总是有一个条件d:SOME_DATE。当日志集合变得非常大时,插入变得非常慢(比我们监视的应用程序生成日志的速度慢),即使在删除了大量索引之后也是如此。所以我们决定将每天的数据放在一个单独的集合中-logs_YYYY-mm-dd,这样索引就更小了,我们甚至不需要日期索引。这很酷,因为大多数报告(因此map/reduce)都是基于日常数据的。然而,我们有一份报告需要涵盖多天 现在是问题。
日志,并使用map/reduce生成各种报告。大多数报告都是基于一天内的数据,所以我总是有一个条件d:SOME_DATE
。当日志
集合变得非常大时,插入变得非常慢(比我们监视的应用程序生成日志的速度慢),即使在删除了大量索引之后也是如此。所以我们决定将每天的数据放在一个单独的集合中-logs_YYYY-mm-dd
,这样索引就更小了,我们甚至不需要日期索引。这很酷,因为大多数报告(因此map/reduce)都是基于日常数据的。然而,我们有一份报告需要涵盖多天
现在是问题。有没有一种方法可以在多个集合上运行map/reduce(或者更准确地说,map),就好像它只有一个集合一样?reduce函数可以调用一次,使用一个键和所有对应的值(但只有当键有多个值时,如果键只有一个值,则根本不会调用它)
它也可以被调用多次,每次调用一个键,并且只调用相应值的一个子集,以及该键先前的reduce结果。这种情况称为重新还原。为了支持re-reduce,您的reduce函数应该是
幂等约简函数有两个关键特性:
- reduce函数的返回值的格式应与它接收的值
的格式相同。因此,如果reduce函数接受字符串数组,则该函数应返回字符串。如果它接受具有多个属性的对象,则应返回包含这些相同属性的对象。这可以确保函数在使用先前reduce的结果调用时不会中断
不要根据它接受的值的数量进行假设。不能保证values
参数包含给定键的所有值。因此,在计算中使用value.length
是非常危险的,应该避免
更新:以下两个步骤在较新的MongoDB版本中不是必需的(甚至可能,我还没有检查)。如果您在map reduce中指定输出集合,它现在可以为您处理以下步骤:
如果reduce函数是幂等函数,那么在映射多个集合时应该不会有任何问题。只需重新减少每个集合的结果:
map = function () {
emit(this._id, this.value);
}
db.tempResult.mapReduce(map, reduce)
第一步
对每个必需的集合运行map reduce,并将结果保存在单个临时集合中。您可以使用以下方法存储结果:
步骤2
使用相同的reduce函数对临时集合运行另一个map reduce。map函数是一个简单的函数,用于从临时集合中选择键和值:
map = function () {
emit(this._id, this.value);
}
db.tempResult.mapReduce(map, reduce)
第二个map reduce基本上是一个re reduce,应该会提供您需要的结果。我使用了map reduce
方法。这里有一个例子
var mapemployee = function () {
emit(this.jobid,this.Name);};
var mapdesignation = function () {
emit(this.jobid, this.Designation);};
var reduceF = function(key, values) {
var outs = {Name:null,Designation: null};
values.forEach(function(v){
if(outs.Name ==null){
outs.Name = v.Name }
if(outs.Name ==null){
outs.Nesignation = v.Designation}
});
return outs;
};
result = db.employee.mapReduce(mapemployee, reduceF, {out: {reduce: 'output'}});
result = db.designation.mapReduce(mapdesignation,reduceF, {out: {reduce: 'output'}});
refreference:如何将所有映射/减少的结果存储在一个集合中,以便以后映射/减少?@ionut bizau:您可以使用finalize函数来完成此操作。查看我的更新答案了解详细信息。太棒了,我没想过!谢谢尼尔斯,你的回答很好。但是,如果我们在两个方向上都有重复的键呢?我建议将tempResult数据保存为{id,value}在通常的id下,并使用map=function()将它们映射为reduce{emit(this.id,this.value);}Oh!我从MongoDB 1.7.4开始发现了mapReduce的有用特性{reduce:“collectionName”}-如果结果集中和旧集合中存在给定键的文档,那么将对这两个值执行reduce操作,结果将在1.8中,您可以使用{out:{reduce:'collectionName'},就像您提到的那样。它非常适合以增量方式聚合统计数据。查看本教程:
var mapemployee = function () {
emit(this.jobid,this.Name);};
var mapdesignation = function () {
emit(this.jobid, this.Designation);};
var reduceF = function(key, values) {
var outs = {Name:null,Designation: null};
values.forEach(function(v){
if(outs.Name ==null){
outs.Name = v.Name }
if(outs.Name ==null){
outs.Nesignation = v.Designation}
});
return outs;
};
result = db.employee.mapReduce(mapemployee, reduceF, {out: {reduce: 'output'}});
result = db.designation.mapReduce(mapdesignation,reduceF, {out: {reduce: 'output'}});