在这样的集合上:
db.consFieldTest.insert([
{ status : "err" }
{ status : "suc" }
{ status : "res" }
{ status : "res" }
{ status : "err" }
{ status : "err" }
{ status : "err" }
]);
聚合结果应如下所示:
{ status: "err", maxCons : 3 },
// (optional) { status: "suc", maxCons : 1 },
// (optional) { status: "res", maxCons : 2 }
实际上如果maxCons
计数器在3处停止就可以了,我需要知道err
状态是否连续发生3次或更多次。
解决问题的想法:
我想到了一个解决方法,就像这样在所有文档上添加一个增量:
{ status : "err", id : 0 },
{ status : "suc", id : 1 },
{ status : "res", id : 2 },
{ status : "res", id : 3 },
{ status : "err", id : 4 },
{ status : "err", id : 5 },
{ status : "err", id : 6 }
然后将它们分组在0-2,1-3,2-4等范围内...... 这将导致这一点:
{ _id : 0
res : [
{ status : "err", id : 0 },
{ status : "suc", id : 1 },
{ status : "res", id : 2 }
]
},
{ _id : 1
res : [
{ status : "suc", id : 1 },
{ status : "res", id : 2 },
{ status : "res", id : 3 },
]
},
{
_id : 2
res : [
{ status : "res", id : 2 },
{ status : "res", id : 3 },
{ status : "err", id : 4 },
]
} ...
有了这个,我可以计算状态err
在连续顺序中发生的频率。
但我不知道怎么写这个group
阶段。
答案 0 :(得分:2)
将此问题视为aggregation framework问题的问题在于,没有将一个文档与另一个文档进行比较的实际概念,因为所有操作既可以一次处理单个文档,也可以将文档分组到一起
因此,找到“连续”条目是您需要一个“全局”变量空间,可以跨文档工作。聚合框架没有任何内容可以做到这一点,但问题可以通过mapReduce来解决:
db.consFieldTest.mapReduce(
function() {
if ( lastSeen != this.status ) {
lastSeen = this.status;
list = [];
counter = 0;
}
list.push(this._id);
counter++;
emit(lastSeen,{ "list": list, "count": counter });
},
function(key,values) {
var mapped = values.map(function(x) { return x.count });
return values[mapped.indexOf(Math.max.apply(Math,mapped))];
},
{
"scope": { "lastSeen": null, "list": [], "counter": 0 },
"out": { "inline": 1 }
}
)
简单地说,这将为当前“状态”值发出“键”,同时保持跟踪连续出现的“列表”和“计数器”的全局变量。列表将在此处构建,仅使用_id
中的数值作为示例,但可以是任何内容:
{ "_id": "err", "values": { "list": [1], "count": 1 }}
{ "_id": "suc", "values": { "list": [2], "count": 1 }}
{ "_id": "res", "values": { "list": [3], "count": 1 }}
{ "_id": "res", "values": { "list": [3,4], "count": 2 }}
{ "_id": "err", "values": { "list": [5], "count": 1 }}
{ "_id": "err", "values": { "list": [5,6], "count": 2 }}
{ "_id": "err", "values": { "list": [5,6,7], "count":3 }}
这基本上是从映射器发出的。注意那里的全局变量的构建。
在reduce函数中,所有相同的键一起处理,或者至少在与reducer在此处工作的相同键的“组”中处理。因此,所有reduce函数都是在该组中找到具有最大计数的值,并在匹配的索引处返回单数项。
你得到的结果基本上是:
{ "_id": "err", "value": { "list": [5,6,7], "count":3 }}
{ "_id": "res", "value": { "list": [3,4], "count": 2 }}
{ "_id": "suc", "value": { "list": [2], "count": 1 }}
mapReduce以“关键”顺序发出最终结果。
是的,JavaScript评估的运行速度比聚合框架慢一点,但是如果没有能力跟踪文档范围内的全局变量,那么这只是其他事情无法完成的事情。