MongoDB - 如何根据文档之间的持续时间进行聚合?

时间:2014-02-27 07:13:52

标签: mongodb

我正在尝试根据事件文档之间的时差将事件文档聚合到会话文档中:

  • if(时间差> 20分钟) - >创建单独的会话
  • 其他 - >合并到同一会话

我正在查看map-reduce和group& aggregate命令,但还没有提出让我这样做的解决方案。

条件

  • 应该是竞争条件证明
  • 将需要处理数据(按时间顺序排列)
  • 事件之间的最大时差= 20min

文档结构

    Event = Schema({
      start: Date,
      end: Date,
    })

    Session = Schema({
      start: Date,
      end: Date,
      duration: Number //will be an aggregate for the time of the events, ignoring the time in between
    })
到目前为止

最佳解决方案(非效率和非种族条件证明)

每个new_event = {start, finish}

    1. matched_events = Sessions.find{ start:{$lt:new_event.finish+20*60*1000},finish:{$gt:new_event.start-20*60*1000}, 
    2. new_session = {start: $min:{matched_events.start}, finish: $max:{matched_events.finish}}

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

为了满足在将新数据添加到集合时实时响应的要求,您可以使用MongoDB复制oplog。 oplog记录每次写入数据库,通常用于允许副本集中的辅助节点跟随对主节点的写入,并将写入应用于辅助节点上的副本。但是,其他应用程序也可以使用它来监视数据库的更新。

要使用此功能,您需要将mongod设置为副本集,这将启用oplog录制。如果您不需要数据复制功能,则可以是单节点副本集。有关如何将独立mongod实例转换为单节点副本集的说明,请参阅this page。简而言之,您重新启动mongod指定--replSet选项,然后使用mongo shell连接并执行rs.initiate()。

完成此操作后,您现在有了一个oplog,它在“本地”数据库中显示为“oplog.rs”capped collection。一旦有了oplog,就可以创建一个tailable cursor来监控写操作。一个tailable游标在概念上类似于Unix tail -f命令:它接收添加到它正在监视的上限集合的每个文档的新结果。

在mongo shell中,它看起来像这样;其他语言驱动程序具有类似的功能:

tailable = DBQuery.Option.tailable + DBQuery.Option.awaitData
db.oplog.rs.find({}).addOption(tailable).forEach(function (d) {
    print('--- op', d.op, 'ns', d.ns)
    printjson(d.o)
    // application logic goes here
})

每次发生写入时,您将获得一个新文档,其中包含详细说明写入的多个字段。你特别感兴趣的是

  • op字段,指示写入是插入还是更新;您可能对插入感兴趣,其中op字段的值为'i'
  • ns字段,表示写入的命名空间(数据库和集合)
  • o字段,即新对象值

例如,前面的程序为每个插入的新文档打印以下内容:

--- op i ns test.c
{ "_id" : ObjectId("5310a0a0ca57fb03897318f8"), "hello" : "world" }

然后,您将在此循环中添加所需的聚合逻辑,检查插入的对象以确定如何将其与先前的文档聚合,从而可能将聚合的文档插入到db中。

您可以在find()中指定查询字词,以确保您只能看到感兴趣的事件。例如,此版本只允许您在“test”数据库的“c”集合上插入:

tailable = DBQuery.Option.tailable + DBQuery.Option.awaitData
db.oplog.rs.find({op:'i', ns:'test.c'}).addOption(tailable).forEach(function (d) {
    // application logic goes here
})

这有帮助吗?还有什么需要进一步澄清的吗?