2015-01-17 67 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

非常感谢尼尔! :) –