我有一些具有相同架构的集合,我想对它们执行合并+聚合。模式很简单,如下所示:
{ 'fr': 1, 'to': 1, 'wg': 213}
{ 'fr': 1, 'to': 2, 'wg': 53}
{ 'fr': 2, 'to': 2, 'wg': 5521}
以下代码适用于合并两个集合,但我想知道是否有更快的解决方案和/或可以以类似的方式合并多个集合而不创建嵌套调用的解决方案:
var c = db.collection('first').find()
c.each(function(err, doc) {
if (err) throw err
if (doc == null) {
console.log('done')
return
}
db.collection('second').findOne({
'fr': doc['fr'],
'to': doc['to']
}, function(err, doc2) {
if (err) throw err
db.collection('my_results').save({
'fr': doc['fr'],
'to': doc['to'],
'wg': doc['wg'] + doc2['wg']
}, function(err) {
if (err) throw err
})
})
})
这里没有绝对免费的操作,因为您无法使用MongoDB进行联接。但是您可以使用mapReduce及其一些功能来获得您想要的输出。
因此,首先创建一个映射器:
var mapper = function () {
emit( { fr: this.fr, to: this.to }, this.wg )
};
然后是一个减速器:
var reducer = function (key,values) {
return Array.sum( values );
};
然后运行mapReduce操作,并将输出设置为不同的集合:
db.first.mapReduce(mapper,reducer,{ "out": { "reduce": "third" } })
请注意此处的"out"选项,本手册部分对此进行了解释。重点是,尽管控制台中输出的统计数据可能会产生误导,但"reduce"语句非常重要。当我们对另一个集合运行相同的代码时,情况就是这样:
db.second.mapReduce(mapper,reducer,{ "out": { "reduce": "third" } })
结果中实际发生的是,第一次操作的输出也被传递到第二次操作的"减少"阶段。
最终结果是,具有相同键值的两个集合中的所有值都将被添加到"第三个"集合中:
{ "_id" : { "fr" : 1, "to" : 1 }, "value" : 426 }
{ "_id" : { "fr" : 1, "to" : 2 }, "value" : 106 }
{ "_id" : { "fr" : 2, "to" : 2 }, "value" : 11042 }
如果您希望fr
和to
是两种可能性的唯一组合,或者甚至运行另一个mapReduce或对这些结果进行聚合,那么您可以让它变得更花哨一些。