我有一个项目集合,
[ a, b, c, d ]
我想将它们成对分组,例如,
[ [ a, b ], [ b, c ], [ c, d ] ]
这将用于计算原始集合中每个项目之间的差异,但该部分使用几种技术来解决,例如本问题中的技术。
我知道这可以通过mapreduce来实现,但是我想知道聚合是否可以。
编辑:这是一个例子,
项的集合;每个项都是一个实际文档。
[
{ 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 }
]
这是聚合框架无法做到的,目前唯一可用于此类操作的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。