我一直在开发中使用mongodb 2.0.4,在部署到生产环境时,我没有意识到它们运行的是2.2.0。我使用的mapReduce函数不再像2.0.4下那样运行,我不知道为什么。
mongodb 2.0.4(注意:M,F,T,I,C,H,R,D的总和应该是144,在这个例子中也是这样):
{
"_id" : "",
"value" : {
"tag" : "",
"networth" : 43558505,
"land" : 201837,
"alive" : 144,
"M" : 86,
"F" : 6,
"T" : 5,
"I" : 10,
"C" : 17,
"H" : 4,
"R" : 12,
"D" : 4,
"gdi" : 15
}
}
mongo 2.2.0(m+f+t+i+c+h+r+d合计为108,实际应为144)
{
"_id" : "",
"value" : {
"tag" : "",
"networth" : 43558505,
"land" : 201837,
"alive" : 144,
"M" : 67,
"F" : 5,
"T" : 3,
"I" : 6,
"C" : 13,
"H" : 3,
"R" : 9,
"D" : 2,
"gdi" : 15
}
}
下面是我正在使用的map/reduce函数:
// Map function
var map = function() {
var key = this.tag;
var value =
{
tag: this.tag,
networth: this.networth,
land: this.land,
alive: this.alive,
gdi: this.gdi,
gov: this.gov
};
emit(key, value);
};
减少功能
var reduce = function(k,vals) {
reducedVals = { tag: k, networth: 0, land: 0, alive: 0, M: 0, F: 0, T: 0, I: 0, C: 0, H: 0, R: 0, D: 0, gdi: 0 };
for (var i = 0; i < vals.length; i++){
reducedVals.networth += vals[i].networth;
reducedVals.land += vals[i].land;
reducedVals.alive += vals[i].alive;
reducedVals.gdi += vals[i].gdi;
if (vals[i].gov == "M") reducedVals.M = reducedVals.M + 1;
if (vals[i].gov == "F") reducedVals.F = reducedVals.F + 1;
if (vals[i].gov == "T") reducedVals.T = reducedVals.T + 1;
if (vals[i].gov == "I") reducedVals.I = reducedVals.I + 1;
if (vals[i].gov == "C") reducedVals.C = reducedVals.C + 1;
if (vals[i].gov == "H") reducedVals.H = reducedVals.H + 1;
if (vals[i].gov == "R") reducedVals.R = reducedVals.R + 1;
if (vals[i].gov == "D") reducedVals.D = reducedVals.D + 1;
}
return reducedVals;
};
执行map reduce
collection.mapReduce(map, reduce, {out: {replace : 'alliances'}, query: {"alive":1}}, function(err, collection) {
// Mapreduce returns the temporary collection with the results
db.close();
});
所以简短的概述…这个集合有一堆分数,格式如下:
"alive" : 1,
"countryNumber" : 47,
"deleted" : 0,
"gdi" : 0,
"gov" : "C",
"land" : 20111,
"name" : "AtheistCelebratingXmas",
"networth" : 9793082,
"protection" : 0,
"rank" : 1,
"resetid" : 407,
"serverid" : 9,
"tag" : "Evolve",
"vacation" : 0
我实际上是按tag
分组,将networth
, land
和alive
列相加。然后检查gov
列的值,并汇总D,R等的总数。这在2.2 vs 2.0.4中不能正常工作,我遗漏了什么特别的原因吗?不管怎样,新的聚合命令会更容易做到这一点吗?我简要地看了一下,可以通过tag
获得该组,networth
和alive
列的总和可以工作-但不知道从哪里开始使用gov列。
从map
函数中emit
对象的形状必须与从reduce
函数返回的对象的形状相同。这是因为当MongoDB决定并行化你的map-reduce时,reduce
调用的结果可以反馈到reduce
。
所以你需要改变你的map
,像这样将emit
的值组合起来,这样它们就和reduce
返回的值具有相同的结构:
var value = {
"tag" : this.tag,
"networth" : this.networth,
"land" : this.land,
"alive" : this.alive,
"gdi" : this.gdi
};
value[this.gov] = 1;
,然后相应地更新您的reduce
函数。
顺便说一句,如果有足够的文档,这在2.0.4中也会失败。只是2.2在何时并行化时使用了不同的阈值。
我接受了JohnnyHK的回答,因为他回答了为什么我的代码不能从一个版本运行到另一个版本;然而,我觉得我应该把我在代码中修改的内容发布出来,以解决这个问题。
地图功能:
var map = function() {
var key = this.tag;
var fields = {
tag: this.tag,
networth: this.networth,
land: this.land,
alive: this.alive,
gdi: this.gdi,
M: 0,
F: 0,
T: 0,
I: 0,
C: 0,
H: 0,
R: 0,
D: 0
};
if (this.gov == "M") fields["M"] = 1
else fields["M"] = 0
if (this.gov == "F") fields["F"] = 1
else fields["F"] = 0
if (this.gov == "T") fields["T"] = 1
else fields["T"] = 0
if (this.gov == "I") fields["I"] = 1
else fields["I"] = 0
if (this.gov == "C") fields["C"] = 1
else fields["C"] = 0
if (this.gov == "H") fields["H"] = 1
else fields["H"] = 0
if (this.gov == "R") fields["R"] = 1
else fields["R"] = 0
if (this.gov == "D") fields["D"] = 1
else fields["D"] = 0
emit(key, fields);
};
Reduce函数:
var reduce = function(k,vals) {
reducedVals = { tag: k, networth: 0, land: 0, alive: 0, M: 0, F: 0, T: 0, I: 0, C: 0, H: 0, R: 0, D: 0, gdi: 0};
for (var i = 0; i < vals.length; i++){
reducedVals.networth += vals[i].networth;
reducedVals.land += vals[i].land;
reducedVals.alive += vals[i].alive;
reducedVals.gdi += vals[i].gdi;
reducedVals.M += vals[i].M;
reducedVals.F += vals[i].F;
reducedVals.T += vals[i].T;
reducedVals.I += vals[i].I;
reducedVals.C += vals[i].C;
reducedVals.H += vals[i].H;
reducedVals.R += vals[i].R;
reducedVals.D += vals[i].D;
}
return reducedVals;
};