用于发票统计的MongoDb聚合或mapreduce?

用于发票统计的MongoDb聚合或mapreduce?,mongodb,Mongodb,我是MongoDb的新手,有一份MapReduce或Aggregation的工作 我有一个发票集合,其中包含以下格式的文档: { date: 'some unix timestamp', total: 12345, paid: true } 我需要在单元格中显示一个表格,其中月份为一月至十二月,每年显示一行,月份总计除以已付和未付。像这样: | Jan | Feb | ... 2013 | 1,222 / 200 | 17

我是MongoDb的新手,有一份MapReduce或Aggregation的工作

我有一个发票集合,其中包含以下格式的文档:

{
    date: 'some unix timestamp',
    total: 12345,
    paid: true
}
我需要在单元格中显示一个表格,其中月份为一月至十二月,每年显示一行,月份总计除以已付和未付。像这样:

     |     Jan     |      Feb      | ...
2013 | 1,222 / 200 |  175 / 2,122  | ...
...
你能帮我搞定mongo命令吗?
也许我最好编写一些JS代码在mongo中执行?

我现在找到了使用MapReduce的解决方案。在这里,它是从PHP使用的:

$map = new MongoCode('
    function() {
        var d = new Date(this.date*1000);
        emit({y: d.getFullYear(), m: d.getMonth()}, {
            total: this.total,
            notPaid: this.paid ? 0 : this.total,
            count: 1
        });
    };
');

$reduce = new MongoCode('
    function(month, values) {
        result = { total: 0, notPaid: 0, count: 0 };
        for (var i = 0; i < values.length; i++) {
            result.total += values[i].total;
            result.notPaid += values[i].notPaid;
            result.count += values[i].count;
        }
        return result;
    };
');

$result = $db->command(array(
    'mapreduce' => 'invoices',
    'map' => $map,
    'reduce' => $reduce,
    'out' => 'temp'
));

echo $result['timeMillis'];

现在,结果在临时集合中,每月一个文档。是否可以对其进行优化或增强?

您可以使用如下聚合框架:

db.invoices.aggregate( [
    {
        "$project" : {
            "yr" : {
                "$year" : "$date"
            },
            "mo" : {
                "$month" : "$date"
            },
            "total" : 1,
            "unpaid" : {
                "$cond" : [
                    "$paid",
                     0,
                    "$total"
                ]
            }
        }
    },
    {
        "$group" : {
            "_id" : {
                "y" : "$yr",
                "m" : "$mo"
            },
            "total" : {
                "$sum" : "$total"
            },
            "unpaid" : {
                "$sum" : "$unpaid"
            }
        }
    }
] )

您可以在最后使用另一个$project来修饰输出,并使用$sort来排序输出,但这是它的基本功能核心。

我并不想说得太苛刻,但如果您亲自尝试编写它,然后在细节上寻求帮助,而不是让社区为您编写,效果会更好。从聚合框架开始,除非你想将结果保存在它自己的集合中。@johnyhk,我完全同意你的看法。我真的是一个通过示例学习的人,我找不到一个像样的示例来获取基本语法。与此同时,我得到了一些有用的东西,最终得到了我自己的答案。现在的问题是,这是否应该用其他方法来实现,也许是聚合。我发现mapreduce语法非常简单明了。如果你喜欢mapreduce语法,那么就坚持使用它,除非它的性能不够好。聚合框架通常更快。好的,谢谢。我也想尝试聚合框架,但现在没有时间。我可能会在某个时候回来用聚合版本更新答案。通过map/reduce解决这个问题的一个很好的例子。请参阅我对聚合框架解决方案的回答,该解决方案可能会更快。谢谢。为什么它比mapreduce快?还有,是否可以使用您的示例,将日期作为unix时间戳?目前,聚合框架$project似乎不支持将长时间存储的unix时间戳直接转换为日期类型,而这正是$year和$month所期望的。您仍然可以这样做,但这将是困难和复杂的-它基本上需要使用带有{$cond:[{$lt:$date,ISODate2012-01-02T00:00:00.valueOf},Jan-2012,{$cond:…etc}的$project…要将所有时间戳范围映射为适当的年-月字符串,您可以进行分组。它比map/reduce快得多,因为它在服务器上本机运行-map-reduce必须生成JavaScript外壳来运行代码,并将数据从BSON转换为JSON等。