2015-01-17 65 views
4

我正在開發一個簡單的財務應用程序,用於跟蹤收入和結果。如何使用總量計算運行總數

爲了簡單起見,我們假設這些都是我的一些文件:

{ "_id" : ObjectId("54adc0659413535e02fba115"), "description" : "test1", "amount" : 100, "dateEntry" : ISODate("2015-01-07T23:00:00Z") } 
{ "_id" : ObjectId("54adc21a0d150c760270f99c"), "description" : "test2", "amount" : 50, "dateEntry" : ISODate("2015-01-06T23:00:00Z") } 
{ "_id" : ObjectId("54b05da766341e4802b785c0"), "description" : "test3", "amount" : 11, "dateEntry" : ISODate("2015-01-09T23:00:00Z") } 
{ "_id" : ObjectId("54b05db066341e4802b785c1"), "description" : "test4", "amount" : 2, "dateEntry" : ISODate("2015-01-09T23:00:00Z") } 
{ "_id" : ObjectId("54b05dbb66341e4802b785c2"), "description" : "test5", "amount" : 12, "dateEntry" : ISODate("2015-01-09T23:00:00Z") } 
{ "_id" : ObjectId("54b05f4ee0933a5c02398d55"), "description" : "test6", "amount" : 4, "dateEntry" : ISODate("2015-01-09T23:00:00Z") } 

我現在想是畫一個「平衡」的圖表,基於這樣的數據:

[ 
    { day:'2015-01-06', amount:50}, 
    { day:'2015-01-07', amount:150}, 
    { day:'2015-01-09', amount:179}, 
... 
] 

換句話說,我需要將我所有的交易按日進行分組,並且每天我需要總計我以前的所有交易(自世界之初以來)。

我已經知道如何通過一天組:

$group: { 
    _id: { 
     y: {$year:"$dateEntry"}, 
     m: {$month:"$dateEntry"}, 
     d: {$dayOfMonth:"$dateEntry"} 
    }, 
    sum: ??? 
} 

但我不知道怎麼回去,總結所有金額。 想象一下,我需要顯示每月餘額報告:我應該運行31個查詢,每天一個總結所有交易金額,除了下一天嗎?當然可以,但不要認爲這是最好的解決方案。

在此先感謝!

+0

我不知道如何準確地編寫查詢,尼爾。如果我只是做了{$ sum:「$ amount」},那麼只有當前的小組交易會包含在我的結果中,而我不想這麼做。請仔細閱讀該問題;) –

+0

對不起。也許我無法解釋我真正想要的,認真的。我不希望每天的所有金額的簡單總和。我想在每天之前總結所有的數額。在我的示例中,2015-01-07將是6月1日和7月1日的金額之和,2015-01-09將是6,7,9月1月金額的總和,以此類推。 –

+0

爲什麼我的問題投下來了?我認爲這將是一個有趣的... –

回答

3

實際上比聚合框架更適合mapReduce,至少在最初的問題解決中。彙總框架沒有關於先前文檔的價值或文檔的前一個「分組」值的概念,所以這就是爲什麼它不能做到這一點。

另一方面,mapReduce有一個「全局範圍」,可以在階段和文檔處理時共享。這將使您在需要的一天結束時獲得當前餘額的「運行總額」。

db.collection.mapReduce(
    function() { 
    var date = new Date(this.dateEntry.valueOf() - 
     (this.dateEntry.valueOf() % (1000 * 60 * 60 * 24)) 
    ); 

    emit(date, this.amount); 
    }, 
    function(key,values) { 
     return Array.sum(values); 
    }, 
    { 
     "scope": { "total": 0 }, 
     "finalize": function(key,value) { 
      total += value; 
      return total; 
     }, 
     "out": { "inline": 1 } 
    } 
)  

這將按日期分組,然後在「最終確定」部分,它會從每一天進行累計總和。

"results" : [ 
      { 
        "_id" : ISODate("2015-01-06T00:00:00Z"), 
        "value" : 50 
      }, 
      { 
        "_id" : ISODate("2015-01-07T00:00:00Z"), 
        "value" : 150 
      }, 
      { 
        "_id" : ISODate("2015-01-09T00:00:00Z"), 
        "value" : 179 
      } 
    ], 

從長遠來看,你將是最好有一個單獨的收集與每一天的條目的改變的更新使用$inc的平衡。也只是做一個$incupsert在每一天的開始創建弘揚與上一交易日餘額的新文檔:

// increase balance 
db.daily(
    { "dateEntry": currentDate }, 
    { "$inc": { "balance": amount } }, 
    { "upsert": true } 
); 

// decrease balance 
db.daily(
    { "dateEntry": currentDate }, 
    { "$inc": { "balance": -amount } }, 
    { "upsert": true } 
); 

// Each day 
var lastDay = db.daily.findOne({ "dateEntry": lastDate }); 
db.daily(
    { "dateEntry": currentDate }, 
    { "$inc": { "balance": lastDay.balance } }, 
    { "upsert": true } 
); 
+0

非常感謝尼爾! :) –