Mongodb 按时间窗口之间的时间间隔分组

Mongodb 按时间窗口之间的时间间隔分组,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我的文件结构如下: { "_id":"5c59c35d8610f702d00e6f70", "ipAddress":"50.116.14.48", "startTime":"2018-02-06T12:01:59.000Z", "endTime":"2018-02-06T12:31:00.000Z", } 我希望能够在15分钟的时间窗口内对事件进行分组。例如考虑到上述文档的结构,我假设此文档在0-15分钟、15-30分钟和30-45分钟内都算是一次事件 结果如下所

我的文件结构如下:

{  
   "_id":"5c59c35d8610f702d00e6f70",
   "ipAddress":"50.116.14.48",
   "startTime":"2018-02-06T12:01:59.000Z",
   "endTime":"2018-02-06T12:31:00.000Z", 
}
我希望能够在15分钟的时间窗口内对事件进行分组。例如考虑到上述文档的结构,我假设此文档在0-15分钟、15-30分钟和30-45分钟内都算是一次事件

结果如下所示:

[  
   {  
      "occurrences":1,
      "startWindow":"2018-02-06T12:00:00.000Z",
      "endWindow":"2018-02-06T12:15:00.000Z"
   },
   {  
      "occurrences":1,
      "startWindow":"2018-02-06T12:15:01.000Z",
      "endWindow":"2018-02-06T12:30:00.000Z"
   },
   {  
      "occurrences":1,
      "startWindow":"2018-02-06T12:30:01.000Z",
      "endWindow":"2018-02-06T12:45:00.000Z"
   }
]
我看到过许多只按时间间隔上的一个日期分组的示例,但是在文档有时间窗口的情况下如何


如何构建此聚合?

如果可以在毫秒而不是字符串上操作,那么很容易。将
startTime
endTime
转换为可以使用和运算符的毫秒数(MongoDB 4.0或更高版本)

将日期“分类”到15分钟范围的公式也很简单:
15
minutes等于
900000
milisonds,因此您可以使用它来获取需要从原始日期开始计算的值

然后,您可以从每个文档生成两个文档(用于
startDate
endDate
),然后使用它们


如果可以在毫秒而不是字符串上进行操作,这很容易。将
startTime
endTime
转换为可以使用和运算符的毫秒数(MongoDB 4.0或更高版本)

将日期“分类”到15分钟范围的公式也很简单:
15
minutes等于
900000
milisonds,因此您可以使用它来获取需要从原始日期开始计算的值

然后,您可以从每个文档生成两个文档(用于
startDate
endDate
),然后使用它们


除了mickl的时间数学,您还需要使用它在开始和结束之间的所有“窗口”中“传播”文档:

db.col.aggregate([
    { $addFields: {
        // an array of 15 min intervals between startTime and endTime
        window: { $range: [ 
            { $floor: { $divide: [ { $toLong: { $toDate: "$startTime" } }, 900000 ] }  }, 
            { $ceil: { $divide: [ { $toLong: { $toDate: "$endTime" } }, 900000 ] }  }
        ] }
    } },
    // 1 document per interval
    { $unwind: "$window" },
    // group by interval
    { $group: {
        _id: "$window",
        occurrences: { $sum: 1 }
    }},
    // to match expected order
    {$sort: {_id:1}},
    // calculate window boundaries
    { $project: {
        _id: 0,
        occurrences: 1,
        startWindow: { $toDate: { $add: [ { $multiply: [ "$_id", 900000 ] }, 1000 ] } },
        endWindow: { $toDate: { $multiply: [ { $add: [ "$_id", 1 ] }, 900000 ] } }        
    } }
])

除了mickl的时间数学,您还需要使用它在开始和结束之间的所有“窗口”中“传播”文档:

db.col.aggregate([
    { $addFields: {
        // an array of 15 min intervals between startTime and endTime
        window: { $range: [ 
            { $floor: { $divide: [ { $toLong: { $toDate: "$startTime" } }, 900000 ] }  }, 
            { $ceil: { $divide: [ { $toLong: { $toDate: "$endTime" } }, 900000 ] }  }
        ] }
    } },
    // 1 document per interval
    { $unwind: "$window" },
    // group by interval
    { $group: {
        _id: "$window",
        occurrences: { $sum: 1 }
    }},
    // to match expected order
    {$sort: {_id:1}},
    // calculate window boundaries
    { $project: {
        _id: 0,
        occurrences: 1,
        startWindow: { $toDate: { $add: [ { $multiply: [ "$_id", 900000 ] }, 1000 ] } },
        endWindow: { $toDate: { $multiply: [ { $add: [ "$_id", 1 ] }, 900000 ] } }        
    } }
])

我应该更详细一些。我向米克尔道歉。假设结束时间现在为“2018-02-06T12:31:00.000Z”,这意味着该文档时间涵盖3个不同的窗口(0-15,15-30,30-45)。如何修改聚合以解决此问题?难道不能添加$match作为第一阶段,以便只保留指定范围内的文档吗?(在弦上应该可以很好地工作)我应该更详细一些。我向米克尔道歉。假设结束时间现在为“2018-02-06T12:31:00.000Z”,这意味着该文档时间涵盖3个不同的窗口(0-15,15-30,30-45)。如何修改聚合以解决此问题?难道不能添加$match作为第一阶段,以便只保留指定范围内的文档吗?(在琴弦上应该可以正常工作)