2016-11-18 35 views
0

我有一个支付集合playerId字段,它是Person集合的_id键。我需要计算一次,一个人的最大支付是多少,并将价值存入人的文档。这就是我要做的事现在:在两个集合中加速mongo更新

db.Person.find().forEach(function(person) { 
    var cursor = db.Payment.aggregate([ 
     {$match: {playerId: person._id}}, 
     {$group: { 
      _id:"$playerId", 
      maxp: {$max:"$amount"} 
     }} 
    ]); 
    var maxPay = 0; 
    if (cursor.hasNext()) { 
     maxPay = cursor.next().maxp; 
    } 
    person.maxPay = maxPay; 
    db.Person.save(person); 
}); 

我想在付款收集寻求maxPay一旦所有人应该更快,但我不知道如何编写代码。请问你能帮帮我吗?

+0

你做错了。向我们展示样本文件的收集和预期结果。另外考虑添加你的MongoDB服务器版本。 – styvane

+0

'个人:{_id},付款方式:{personId,金额}'。预期的人有场maxPay。使用mongodb 3.2 – awfun

回答

1

您可以只运行一个聚合流水线操作,它最初有一个流水线操作,用于对Payment集合执行“左连接”。为了从作为一个名为payments的数组嵌入结果文档中的正确集合(付款)中获取数据,这是必需的。

前述$unwind管道解构嵌入式payments阵列即,它会为每一个payments数据字段的每一个元素的新记录和。它基本上平整了将在下一个阶段有用的数据。

在此$group流水线阶段,您可以通过应用累加器表达式来计算所需的聚合。如果比如你Person架构中有您希望保留其他领域,那么$first蓄电池经营者应在除了足够的$max运营商的额外maxPay领域。


UPDATE

不幸的是,没有运营商 “包括所有字段” 在$group聚集流水线操作。这是因为流水线步骤主要用于对来自收集字段(sum,avg等)的数据进行分组和计算/汇总,并且返回所有集合的字段不是流水线的预期用途。组管道运算符类似于SQL的GROUP BY子句,除非使用任何聚合函数(MongoDB中的累加器运算符),否则不能使用GROUP BY。同样,如果你需要保留大部分字段,你也必须在MongoDB中使用聚合函数。在这种情况下,您必须将$first应用于您要保留的每个字段。

您还可以使用引用根文档的系统变量$$ROOT。请将本文件的所有字段的字段中$group管道内,例如:

{ 
    "$group": { 
     "_id": "$_id", 
     "maxPay": { "$max": "$payments.amount" }, 
     "doc": { "$first": "$$ROOT" } 
    } 
} 

这种方法的缺点是,你需要进一步$project管道,使它们符合重塑场原始模式,因为生成的管道中的文档只有三个字段; _id,maxPay和嵌入式doc字段。


最后的流水线阶段,$out,写入产生的聚合管道输送到同一个集合的文件,类似于用新的结果集合原子取代现有的收集更新Person集合。 $out操作不会更改以前集合中存在的任何索引。如果汇聚失败,则$out操作不更改的现有集合:

db.Person.aggregate([ 
    { 
     "$lookup": { 
      "from": "Payment", 
      "localField": "_id", 
      "foreignField": "playerId", 
      "as": "payments" 
     } 
    }, 
    { "$unwind": { 
     "path": "$payments", 
     "preserveNullAndEmptyArrays": true 
    } }, 
    { 
     "$group": { 
      "_id": "$_id", 
      "maxPay": { "$max": "$payments.amount" }, 
      /* extra fields for demo purposes 
      "firstName": { "$first": "$firstName" }, 
      "lastName": { "$first": "$lastName" } 
      */ 
     } 
    }, 
    { "$out": "Person" } 
]) 
+0

哇,我不知道$ lookup。但是它有一个问题。只有至少有一次付款的人才能被保存。另外,还有什么方法可以保存其他人的领域而不用全部列出? – awfun

+0

在'$ unwind'中包含'preserveNullAndEmptyArrays'选项应该解决第一个问题(如更新后的答案)。至于另一个问题,我在同一个更新中回答了这个问题。 – chridam

+1

非常感谢您的解释! – awfun

相关问题