首先,背景。我曾经有一个集合logs
并使用map / reduce来生成各种报告。大多数这些报告都是基于一天内的数据,所以我总是有条件d: SOME_DATE
。当logs
集合变得非常大时,插入变得极其缓慢(比我们监视的应用程序生成日志的速度慢),即使在丢弃大量索引之后也是如此。因此我们决定将每一天的数据放在一个单独的集合中 - logs_YYYY-mm-dd
- 这样索引就更小了,我们甚至不需要索引日期。这很酷,因为大多数报告(因此map / reduce)都是每日数据。但是,我们有一份报告,我们需要覆盖多天。
现在问题。有没有办法在多个集合上运行map / reduce(或更确切地说,地图),就好像它只是一个?
答案 0 :(得分:35)
可以使用键和所有对应值调用一次reduce函数(但仅当键有多个值时 - 如果只有1个值,则根本不会调用它关键)。
也可以多次调用它,每次都使用一个键,只有相应值的子集,以及之前的该键的减少结果。此方案称为重新减少。为了支持重新缩减,您的reduce函数应为idempotent。
幂等减少函数有两个关键特性:
values
参数包含 all 的值给定的密钥。因此,在计算中使用values.length
是非常危险的,应该避免使用。更新:最新的MongoDB版本不需要以下两个步骤(甚至可能,我还没有检查过)。如果您在map-reduce options中指定输出集合,它现在可以为您处理这些步骤:
{ out: { reduce: "tempResult" } }
如果你的reduce函数是幂等的,你应该没有任何问题地图减少多个集合。只需重新减少每个集合的结果:
对每个必需的集合运行map-reduce,并将结果保存在单个临时集合中。您可以使用finalize function:
存储结果finalize = function (key, value) {
db.tempResult.save({ _id: key, value: value });
}
db.someCollection.mapReduce(map, reduce, { finalize: finalize })
db.anotherCollection.mapReduce(map, reduce, { finalize: finalize })
在临时集合上运行另一个map-reduce,使用相同的reduce函数。 map函数是一个简单的函数,用于从临时集合中选择键和值:
map = function () {
emit(this._id, this.value);
}
db.tempResult.mapReduce(map, reduce)
这第二个map-reduce基本上是一个重新缩减,应该可以为你提供所需的结果。
答案 1 :(得分:1)
我使用了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'}});
参考:http://www.itgo.me/a/x3559868501286872152/mongodb-join-two-collections