Mongodb 聚合 - 今天按小时分组

Posted

技术标签:

【中文标题】Mongodb 聚合 - 今天按小时分组【英文标题】:Mongodb Aggregate - Grouping by hour for today 【发布时间】:2020-05-04 22:47:49 【问题描述】:

我想知道是否有人可以帮助我正确设置聚合函数。我正在尝试计算我的健身访问量。我有访问表,其中保存了每次访问(从,到)日期。还保存了对某些服务的子访问。

[
  "from": ISODate("2020-01-17T10:23:27.645Z"),
  "to": ISODate("2020-01-17T12:23:28.760Z"),
  "visits": [
    
      "from": ISODate("2020-01-17T10:23:27.646Z"),
      "to": ISODate("2020-01-17T10:30:28.760Z"),
      "service": ObjectId("5e05f17d6b7f7920d4a62403")
    ,
    
      "from": ISODate("2020-01-17T10:30:29.760Z"),
      "to": ISODate("2020-01-17T12:23:28.760Z"),
      "service": ObjectId("5d05f17dt57f7920d4a62404")
    
  ],
  ...
,

  "from": ISODate("2020-01-17T10:40:00.000Z"),
  "to": ISODate("2020-01-17T11:30:28.760Z"),
  "visits": [
    
      "from": ISODate("2020-01-17T10:40:00.000Z"),
      "to": ISODate("2020-01-17T11:30:28.760Z"),
      "service": ObjectId("h505f17s6b2f7920d4a6295y")
    
  ],
  ...

]

如果当前时间是 13:35,我想从 00:00 获得今天的结果,然后一直到 13:00,例如:

[
  'date': '2020-01-18T00:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T00:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T00:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T01:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T02:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T03:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T04:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T05:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T06:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T07:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T08:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T09:00:0.000Z'
  'visits': 0
,

  'date': '2020-01-18T010:00:0.000Z'
  'visits': 2
,

  'date': '2020-01-18T11:00:0.000Z'
  'visits': 2
,

  'date': '2020-01-18T12:00:0.000Z'
  'visits': 1
,

  'date': '2020-01-18T13:00:0.000Z'
  'visits': 0
]

尝试了太多示例,但没有任何效果,请帮助!

【问题讨论】:

【参考方案1】:

解释

    如果我们使用$$NOW,我们会得到当前日期。如果您手动设置currDatetodaynextDay,MongoDB 聚合将限制所需的值。

    现在,我们计算从today (yyyy-MM-dd 00:00:00) - currDate (yyyy-MM-dd 13:35:00) ~ 13 小时和$range运算符创建数组

    我们展平区间并应用过滤

你可以使用这样的查询:

db.collection.aggregate([
  
    $addFields: 
      nextDay: 
        $add: [
          
            $dateFromString: 
              dateString: 
                $substr: [
                  
                    $toString: "$$NOW"
                  ,
                  0,
                  10
                ]
              ,
              format: "%Y-%m-%d"
            
          ,
          
            $multiply: [
              24,
              60,
              60,
              1000
            ]
          
        ]
      ,
      today: 
        $dateFromString: 
          dateString: 
            $substr: [
              
                $toString: "$$NOW"
              ,
              0,
              10
            ]
          ,
          format: "%Y-%m-%d"
        
      ,
      currDate: 
        $dateFromString: 
          dateString: 
            $substr: [
              
                $toString: "$$NOW"
              ,
              0,
              13
            ]
          ,
          format: "%Y-%m-%dT%H",
          timezone: "-01"
        
      
    
  ,
  
    $addFields: 
      interval: 
        $range: [
          0,
          
            $add: [
              
                $divide: [
                  
                    $subtract: [
                      "$currDate",
                      "$today"
                    ]
                  ,
                  
                    $multiply: [
                      60,
                      60,
                      1000
                    ]
                  
                ]
              ,
              1
            ]
          ,
          1
        ]
      
    
  ,
  
    $unwind: "$interval"
  ,
  
    $addFields: 
      date: 
        $add: [
          "$today",
          
            $multiply: [
              "$interval",
              60,
              60,
              1000
            ]
          
        ]
      ,
      nextHour: 
        $add: [
          "$today",
          
            $multiply: [
              
                $add: [
                  "$interval",
                  1
                ]
              ,
              60,
              60,
              1000
            ]
          
        ]
      
    
  ,
  
    $project: 
      _id: 0,
      date: 1,
      today: 1,
      nextDay: 1,
      visits: 
        $reduce: 
          input: "$visits",
          initialValue: 0,
          in: 
            $add: [
              "$$value",
              
                $cond: [
                  
                    $or: [
                      
                        $and: [
                          
                            $gte: [
                              "$$this.from",
                              "$date"
                            ]
                          ,
                          
                            $lte: [
                              "$$this.from",
                              "$nextHour"
                            ]
                          
                        ]
                      ,
                      
                        $and: [
                          
                            $lte: [
                              "$date",
                              "$$this.to"
                            ]
                          ,
                          
                            $gte: [
                              "$date",
                              "$$this.from"
                            ]
                          
                        ]
                      
                    ]
                  ,
                  1,
                  0
                ]
              
            ]
          
        
      
    
  ,
  
    $match: 
      $expr: 
        $and: [
          
            $gte: [
              "$date",
              "$today"
            ]
          ,
          
            $lte: [
              "$date",
              "$nextDay"
            ]
          ,

        ]
      
    
  ,
  
    $group: 
      _id: "$date",
      visits: 
        $sum: "$visits"
      
    
  ,
  
    $sort: 
      _id: 1
    
  
])

MongoPlayground

JS设置,点击here

如果你想要更优雅的方式,你可以尝试this 解决方案

【讨论】:

我们可以使用 javascript 变量中的 startDate 和 endDate 吗? 当然。设置 currDatenextDaytoday 看看https://mongoplayground.net/p/tYDbBghxn16 确保您复制粘贴了我的代码的最新版本 好的,谢谢你帮助我。现在我有最后一个问题,它正在承受我的健身负担。就像我的访问时间是从 10:00 到 12:30,我需要显示在 10:00 访问 1 次,在 11:00 访问 1 次,并且在 12:00 还访问 1 次。我怎样才能达到这个逻辑?

以上是关于Mongodb 聚合 - 今天按小时分组的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB聚合查询返回集合中每年每月的条目总数,按位置值分组

MongoDB在每日分组中聚合[重复]

在 mongodb 本地时区聚合

MongoDB按聚合查询分组

你如何从 Mongo 日期字段中获取 DayHours?

你如何从 Mongo 日期字段中获取 DayHours?