2016-11-18 33 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

相關問題