计算连续字段出现的最高数量



在这样的集合上:

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阶段。

将此作为聚合框架问题处理的问题是,没有实际的概念将一个文档与另一个文档进行比较,因为所有操作要么一次处理单个文档,要么将文档分组在一起。

所以找到"连续"条目是你需要一个可以跨文档工作的"全局"变量空间。聚合框架没有办法做到这一点,但是这个问题可以用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 }
    }
)

简单地说,这将为当前"状态"值发出一个"键",同时保留跟踪连续出现的"列表"one_answers"计数器"的全局变量。列表将在这里建立,仅使用_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计算比聚合框架运行得慢一点,但是如果没有在文档范围内跟踪全局变量的能力,这是无法完成的。

相关内容

  • 没有找到相关文章

最新更新