【问题标题】:MongoDb aggregation Group by DateMongoDb 聚合按日期分组
【发布时间】:2013-11-25 20:13:58
【问题描述】:

我正在尝试按名为“foo”{ _id, TimeStamp } 的集合的时间戳进行分组

db.foos.aggregate(
[
   {$group : { _id : new Date (Date.UTC({ $year : '$TimeStamp' },{ $month : '$TimeStamp' },{$dayOfMonth : '$TimeStamp'}))       }}
])

期望有很多日期,但结果只有一个日期。我使用的数据是正确的(有许多 foo 和不同的日期,除了 1970 年)。日期解析有问题,但我还不能解决。

{
    "result" : [ 
        {
            "_id" : ISODate("1970-01-01T00:00:00.000Z")
        }
    ],
    "ok" : 1
}

试过这个:

db.foos.aggregate(
[
   {$group : { _id : { year : { $year : '$TimeStamp' }, month : { $month : '$TimeStamp' }, day : {$dayOfMonth : '$TimeStamp'} }, count : { $sum : 1 }       }},
   {$project : { parsedDate : new Date('$_id.year', '$_id.month', '$_id.day') , count : 1, _id : 0} }
])

结果:

uncaught exception: aggregate failed: {
    "errmsg" : "exception: disallowed field type Date in object expression (at 'parsedDate')",
    "code" : 15992,
    "ok" : 0
}

还有那个:

db.foos.aggregate(
[
   {$group : { _id : { year : { $year : '$TimeStamp' }, month : { $month : '$TimeStamp' }, day : {$dayOfMonth : '$TimeStamp'} }, count : { $sum : 1 }       }},
   {$project : { parsedDate : Date.UTC('$_id.year', '$_id.month', '$_id.day') , count : 1, _id : 0} }
])

在结果中看不到日期

{
    "result" : [ 
        {
            "count" : 412
        }, 
        {
            "count" : 1702
        }, 
        {
            "count" : 422
        }
    ],
    "ok" : 1
}

【问题讨论】:

  • 您不能在聚合中使用 Javascript - 即您的新 Date 不会根据您尝试传递给它的值进行评估。
  • 如果您想将时间转换为日期(每天或每小时),请在此处查看一些示例:kamsky.org/1/post/2013/03/…
  • Date.UTC 是问题所在。我认为 mongo 中不存在这样的构造。
  • @AsyaKamsky 我喜欢你的博客 :-)。你能把它的链接放在你的个人资料里吗?
  • 从 3.0 开始,有一个 dateToString 格式让生活更轻松docs.mongodb.com/manual/reference/operator/aggregation/…

标签: mongodb aggregation-framework


【解决方案1】:

这取决于您是否希望在最终输出中将日期作为 ISODate 类型。如果是这样,那么您可以做以下两件事之一:

  1. 从您的时间戳中提取$year$month$dayOfMonth,然后从中重建一个新日期(您已经在尝试这样做,但您使用的语法不起作用在聚合框架中)。

  2. 如果原始时间戳是 ISODate() 类型,那么您可以进行日期算术以从时间戳中减去小时、分钟、秒和毫秒,以获得“四舍五入”到当天的新日期。

有一个example of 2 here

以下是您的做法 1. 我假设您的所有日期都是今年,但您可以轻松调整数学以适应您最早的日期。

project1={$project:{_id:0, 
                   y:{$subtract:[{$year:"$TimeStamp"}, 2013]},
                   d:{$subtract:[{$dayOfYear:"$TimeStamp"},1]}, 
                   TimeStamp:1, 
                   jan1:{$literal:new ISODate("2013-01-01T00:00:00")}
         } };
project2={$project:{tsDate:{$add:[
                       "$jan1",
                       {$multiply:["$y", 365*24*60*60*1000]},
                       {$multiply:["$d", 24*60*60*1000]}
         ] } } };

样本数据:

db.foos.find({},{_id:0,TimeStamp:1})
{ "TimeStamp" : ISODate("2013-11-13T19:15:05.600Z") }
{ "TimeStamp" : ISODate("2014-02-01T10:00:00Z") }

聚合结果:

> db.foos.aggregate(project1, project2)
{ "tsDate" : ISODate("2013-11-13T00:00:00Z") }
{ "tsDate" : ISODate("2014-02-01T00:00:00Z") }

【讨论】:

    【解决方案2】:
    db.foos.aggregate(
        [   
            {   $project : { day : {$substr: ["$TimeStamp", 0, 10] }}},        
            {   $group   : { _id : "$day",  number : { $sum : 1 }}},
            {   $sort    : { _id : 1 }}        
        ]
    )
    

    按日期分组可以在聚合框架中分两步完成,如果需要排序,还需要额外的第三步来对结果进行排序:

    1. $project 结合 $substr 从每个文档中获取 ISODate 对象的前 10 个字符 (YYYY:MM:DD)(结果是包含字段“_id”和“day”的文档集合);李>
    2. $group 按天分组,为每个匹配的文档添加(求和)数字 1;
    3. $sort 按“_id”升序,即上一个聚合步骤的日期 - 如果需要排序结果,这是可选的。

    此解决方案不能利用像db.twitter.ensureIndex( { TimeStamp: 1 } ) 这样的索引,因为它会将 ISODate 对象动态转换为字符串对象。对于大型集合(数百万个文档),这可能是性能瓶颈,应该使用更复杂的方法。

    【讨论】:

    • 这可能会或可能不会回答这个问题,但如果它解释了它为什么回答这个问题,这将是一个更好的答案并且对每个人都更有用。只提供一堆代码而不做任何解释是没有多大帮助的。
    【解决方案3】:

    这是我在我的一个项目中使用的:

       collection.aggregate(
          // group results by date
          {$group : {
            _id : { date : "$date" }
            // do whatever you want here, like $push, $sum...
          }},
    
          // _id is the date
          {$sort : { _id : -1}},                        
          {$orderby: { _id : -1 }})
        .toArray()
    

    其中 $date 是 mongo 中的 Date 对象。我得到按日期索引的结果。

    【讨论】:

      猜你喜欢
      • 2019-05-17
      • 1970-01-01
      • 1970-01-01
      • 2021-09-28
      • 2021-07-16
      • 2016-04-07
      • 1970-01-01
      • 1970-01-01
      • 2018-04-25
      相关资源
      最近更新 更多