使用mongo聚合成对分组文档

时间:2014-12-31 19:29:50

标签: mongodb mapreduce mongodb-query aggregation-framework

我有一系列项目,

[ a, b, c, d ]

我想成对分组,例如,

[ [ a, b ], [ b, c ], [ c, d ] ]

这将用于计算原始集合中每个项目之间的差异,但该部分使用多种技术解决,例如this question中的那个。

我知道这可以通过map reduce实现,但我想知道聚合是否可行。

编辑:这是一个例子,

物品的收集;每个项目都是一个实际的文件。

[
    { val: 1 },
    { val: 3 },
    { val: 6 },
    { val: 10 },
]

分组版本:

[
    [ { val: 1 }, { val: 3 } ], 
    [ { val: 3 }, { val: 6 } ],
    [ { val: 6 }, { val: 10 } ]
]

结果集合(或聚合结果):

[
    { diff: 2 },
    { diff: 3 },
    { diff: 4 }
]

1 个答案:

答案 0 :(得分:4)

这是聚合框架无法完成的事情,目前唯一可用于此类操作的MongoDB方法是mapReduce。

原因是聚合框架无法引用管道中的任何其他文档而不是当前文档。这实际上适用于"分组"管道阶段也是如此,因为即使事情被分组在"键"你不能以你想要的方式真正处理个别文件。

另一方面,MapReduce有一个功能可以让你在这里做你想做的事情,而且它甚至不能直接"与聚合有关。实际上,它具有全局范围的变量"跨越所有阶段。并且有一个"变量"基本上"存储最后一个文件"是实现结果所需的一切。

所以这是非常简单的代码,事实上没有"减少"需要:

db.collection.mapReduce(
    function () {
      if (lastVal != null)
        emit( this._id, this.val - lastVal );
      lastVal = this.val;
    },
    function() {}, // mapper is not called
    {
        "scope": { "lastVal": null },
        "out": { "inline": 1 }
    }
)

这给你一个像这样的结果:

{
    "results" : [
            {
                    "_id" : ObjectId("54a425a99b8bcd6f73e2d662"),
                    "value" : 2
            },
            {
                    "_id" : ObjectId("54a425a99b8bcd6f73e2d663"),
                    "value" : 3
            },
            {
                    "_id" : ObjectId("54a425a99b8bcd6f73e2d664"),
                    "value" : 4
            }
    ],
    "timeMillis" : 3,
    "counts" : {
            "input" : 4,
            "emit" : 3,
            "reduce" : 0,
            "output" : 3
    },
    "ok" : 1
}

这真的只是挑选了一些独特的东西"作为发出的_id值而不是任何特定值,因为所有这些都是不同文档上的值之间的差异。

全局变量通常是这些类型"配对的解决方案。聚合或生成"运行总计"。现在,聚合框架无法访问全局变量,即使它可能很好。 mapReduce框架有它们,因此可以公平地说它们也应该可用于聚合框架。

现在他们不是,所以坚持使用mapReduce。