与时间序列汇总中上一个记录的时间差

时间:2018-09-21 06:54:43

标签: mongodb aggregation-framework

我收集了不同演员的活动集。现在,我需要计算每个参与者发生的事件数量,即自上次事件发生以来的时间x。

一个更具体的示例:由不同参与者进行的登录事件的集合。自上次登录以来少于8小时发生的每个登录事件均应忽略。因此,假设我在下午2点登录,然后在晚上11点登录,我们想要的计数为2。如果我要在下午2点登录,然后在下午5点登录,则该计数必须为1。

我真的没有看到使用聚合框架解决此问题的可行方法。一种可能的解决方案是为每个记录计算(并保存)上一个事件之间的时间。但是我觉得应该有一个更好的解决方案。

有人能指出我正确的方向吗?并没有真正找到与此用例相似的用例。

如果我的问题不清楚,请告诉我!


修改:

一个例子:

简化事件:

[{
    _id: 1,
    actor: X,
    date: ISODate("2018-09-20T18:00:00.000Z")
},
{
    _id: 2,
    actor: X,
    date: ISODate("2018-09-21T05:00:00.000Z") // 11 hours since previous
},
{
    _id: 3,
    actor: X,
    date: ISODate("2018-09-21T07:00:00.000Z") // 2 hours since previous
},
{
    _id: 4,
    actor: Y,
    date: ISODate("2018-09-21T06:00:00.000Z")
},
{
    _id: 5,
    actor: Y,
    date: ISODate("2018-09-21T09:00:00.000Z") // 3 hours since previous
}]

预期输出:

[{
    _id: X,
    count: 2 // 3 events, but one is less than 8 hours since previous
},
{
    _id: Y,
    count: 1 // 2 events, but one is less than 8 hours since previous
}]

1 个答案:

答案 0 :(得分:1)

您可以比较不同文档中的值,方法是将它们分组为数组并对其进行迭代。就您而言,$reduce可能是最简单的方法:

db.collection.aggregate([
  // ensure order
  { $sort: { date: 1 } }, 
  // get all dates per actor
  { $group: { _id: "$actor", dates: { $push: "$date" } } }, 
  { $addFields: {
      // iterate dates
      events: { $reduce: {
          input: "$dates",
          initialValue: { last: null, count: 1 },
          // increment counter if difference is > than 8 * 60 * 60 * 1000 millis 
          in: { last: "$$this", count: { $add: [
              "$$value.count", 
              { $cond: [ 
                  {$gt: [ { $subtract: [ "$$this", "$$value.last" ] }, 28800000 ] }, 
                  1, 
                  0 
              ] }
          ] } }
      } }
  } },
  { $project: { count: "$events.count" } }
])

在大型数据集上会变慢。在这种情况下,您可能需要在插入时预先汇总计数器。