日期聚合框架

时间:2013-03-20 15:04:27

标签: node.js mongodb date aggregation-framework

我正试图在Mongo中按日期聚合数据,但我无法实现我想要的效果。 现在,我正在使用它:

db.aggregData.aggregate( { $group: {_id: "$Date".toString(),  
                                   tweets: { $sum: "$CrawledTweets"} } }, 
                         { $match:{ _id: {$gte: ISODate("2013-03-19T12:31:00.247Z") }}}, 
                         { $sort: {Date:-1} } 
                       )

结果如下:

"result" : [
                {
                        "_id" : ISODate("2013-03-19T12:50:00.641Z"),
                        "tweets" : 114
                },
                {
                        "_id" : ISODate("2013-03-19T12:45:00.631Z"),
                        "tweets" : 114
                },
                {
                        "_id" : ISODate("2013-03-19T12:55:00.640Z"),
                        "tweets" : 123
                },
                {
                        "_id" : ISODate("2013-03-19T12:40:00.628Z"),
                        "tweets" : 91
                    },
                {
                        "_id" : ISODate("2013-03-19T12:31:00.253Z"),
                        "tweets" : 43
                },
                {
                        "_id" : ISODate("2013-03-19T13:20:00.652Z"),
                        "tweets" : 125
                },
                {
                        "_id" : ISODate("2013-03-19T12:31:00.252Z"),
                        "tweets" : 30
                }
 ],
        "ok" : 1

似乎做了这项工作,但经过进一步检查,我们发现有重复:
ISODate(“2013-03-19T12:31:00.253Z”)和ISODate(“2013-03-19T12:31:00.252Z”)。
唯一改变的是Z之前的最后一位。

所以这是我的问题。这部分是什么?如何在聚合中忽略它?

提前谢谢。

编辑:我想按日期汇总,所以全年/月/日+小时和分钟。我不在乎其余的事情。

编辑:我在mongolab上的数据库,所以我在2.2

好吧,我做了另一种方式:我将所有日期保存为秒/毫秒为0.所以我可以保留一个简单的聚合,而不是更多的代码服务器端,感谢moment.js

3 个答案:

答案 0 :(得分:6)

你试图按“整个”日期聚合,换句话说是从ISODate()中删除时间,对吗?有几种方法可以做到这一点,我在我的博客中详细描述了这些方法,名为

Stupid Date Tricks with Aggregation Framework

您可以在那里看到完整的逐步细分,但总结一下,您有两种选择:

  • 如果您不关心汇总后的值为ISODate(),那么您可以使用{$year}{$month}{$dayOfMonth}运算符{$project}阶段将YMD拉到{$ group}上。

  • 如果你关心保留ISODate的分组值,你可以{$subtract} {$project}阶段的时间部分,并留下ISODate()类型 - 需要注意的是,此方法需要MongoDB 2.4 (just released),它增加了对日期算术和$millisecond运算符的支持(参见博文中的确切代码)。

这可能是你想要的:

db.aggregData.aggregate([
  { 
    $project:{ 
        CrawledTweets: 1,
        newDate: { 
            year:{$year:"$Date"}, 
            month: {$month:"$Date"}, 
            day: {$dayOfMonth:"$Date"}, 
            hour: {$hour: "$Date"}, 
            min: {$minute: "$Date"}
        }   
    }   
  },
  { 
    $group: {
        _id: "$newDate",
        tweets: { $sum: "$CrawledTweets"}
    }   
  }
])

答案 1 :(得分:1)

如果不是Mongo专家而且不知道你的db字段,我会想出这样的东西。也许你可以在此基础上建立:

db.aggregData.aggregate(
{ 
    $project:{ 
        CrawledTweets: 1,
        groupedTime: { 
            year:{$year:"$_id"}, 
            month: {$month:"$_id"}, 
            day: {$dayOfMonth:"$_id"}, 
            hour: {$hour: "$_id"}, 
            min: {$minute: "$_id"}
        }   
    }   
},
{ 
    $group: {
        _id: { groupedTime: "$CrawledTweets" },
        tweets: { $sum: "$tweets"}
    }   
}
)

答案 2 :(得分:1)

您现在可以使用MongoDB日期聚合运算符,我在我的博客上发布了一个关于Schema设置的帖子,在Node.js中使用它等等:

http://smyl.es/how-to-use-mongodb-date-aggregation-operators-in-node-js-with-mongoose-dayofmonth-dayofyear-dayofweek-etc/