MongoDB - 时间序列子文档的范围查询

问题描述:

我对Mongo非常陌生,刚刚开始讨论核心概念......我正在实现时间序列数据模式,并计划尝试模式建议在这里:MongoDB as a Time Series Database,这也出现在一些Mongo的介绍。MongoDB - 时间序列子文档的范围查询

我明白这个模式,但是我很难弄清楚如何在一个日期范围内查询它。更具体地说,有人可以举例说明如何在上面的链接中查询架构以检索跨越多个小时/天的1分钟系列?理想情况下,不需要在Mongo之外进行后期处理。

Mongo文档和聚合管道似乎主要关注处理数组而不是嵌套子文档...... TIA。

编辑:为了更清晰添加到我试图解决特定的问题...

比方说,我在存储间隔1分钟的数据,每天一个父文档,使用下面的架构(从上方连结后剪断):

{ 
    timestamp_hour: ISODate("2013-10-10T23:00:00.000Z"), 
    type: “spot_EURUSD”, 
    values: { 
    0: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343}, 
    1: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343}, 
    …, 
    22: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343}, 
    23: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343} 
    } 
} 

什么是最有效的/高效的方式满足形式的查询:“给我值的时间列表,每分钟1日起对2013- 09-25在下午1点37分,结束于2013-10-15下午2点56分“?

有从你给的是应该指向你在正确的方向的链接@jtromans评论:

...你应该继续相应的“分档”您的资料到需要满足最高分辨率标准

因此,假如你有一个像下面这样的模式:

{ 
    timestamp_hour: ISODate(...), 
    values: { 
     0: {}, 
     1: {}, 
     ... 
     59: {} 
    } 
} 

然后你有一个子文档每分钟,W HICH将允许您以满足您的查询相当简单(找到在第4分钟每次,例如:

collection.find({}, {"values.3": 1}) 

这只是一个投影仅筛选您感兴趣的分钟值,因为它是另有一个完整。表扫描,你可能想要在timestamp_hour字段中包含日期范围来限制搜索。您可以使用聚合如果你喜欢项目的值,以更好地满足您期望的格式,例如:

collection.aggregate([ 
    {$project: {val: "$values.1"}} 
]) 

如果您需要能够对小时,秒,或其他的时间部分过滤,那么你将需要你的模式中的那些箱或键,例如装箱秒和分钟:

{ 
    timestamp_hour: ISODate(...), 
    minutes: { 
     0: { 
      seconds: { 
       0: ... 
      } 
     }, 
     ... 
    } 
} 

例如添加其他值作为重点,使他们能够被索引和过滤:

{ 
    timestamp_hour: ISODate(...), 
    hour_of_day: 0, 
    day_of_month: 1 
    minutes: { 
     ... 
    } 
} 

请注意,我在这里使用的文档每小时的方法,你必须根据你的数据和需求来决定,如果这适合你或如果你想每分钟,每天等文件。

编辑:下面是一个例子,更好地匹配编辑的问题:

db.ts.aggregate([ 
    { 
     $match: { 
      timestamp_hour: {$lte: {ISODate("2013-09-25")}, $gte: {ISODate("2013-10-15")}} 
     } 
    }, 
    { 
     $project: { 
      hours: {$objectToArray: "$values"} 
     } 
    }, 
    { 
     $unwind: "$hours" 
    }, 
    { 
     $project: { 
      hour_index: "$hours.k", 
      minutes: {$objectToArray: "$hours.v"} 
     } 
    }, 
    { 
     $unwind: "$minutes" 
    }, 
    { 
     $project: { 
      reconstructed_date: {$dateFromParts: { 
       year: {$year: "$timestamp_hour"}, 
       month: {$month: "$timestamp_hour"}, 
       day: {$day: "$timestamp_hour"}, 
       hour: "$hour_index", 
       minute: "$minutes.k", 
      }} 
      value: "$minutes.v" 
     } 
    }, 
    { 
     $match: { 
      reconstructed_date: {$lte: {ISODate("2013-09-25T13:37:00.000Z")}, $gte: {ISODate("2013-10-15T14:56:00.000Z")}} 
     } 
    } 
]) 

我不会试图获取时区在这其中的权利,这是给你的!

+0

感谢您的回答,但我认为我所寻找的可能比您所描述的要简单。我只想做一个香草日期范围查询,而不是过滤特定的时间段。为了清晰起见,我编辑了我的问题。有什么想法吗? – stephenrs

+0

啊,我明白了。你需要在'$ project'阶段使用'$ objectToArray',这样你就可以在后面的阶段使用'$ unwind'(展开只适用于数组;因为这个原因你可能想从对象切换到数组) ,因为你的聚合会变得混乱);获取所有会议记录,而不是特定会议记录,然后选择那一分钟内的内容(第一项,如果该值是数组或子文档而不是值),则需要执行此操作_twice_。 –

+0

时间范围查询也会变得复杂 - 您需要在'timestamp_hour'字段中初始化一个'$ match'阶段(为了将文档设置为合理的大小,并且您需要小心界限) ,你需要一个'$ project'阶段来创建带有小时/分钟/秒值的新字段,所以你有一个最后的'$ match'阶段在第一天/最后一天过滤掉不想要的值。总的来说,变得相当复杂,我想要在生产大小的数据集上运行测试,以确保查询性能一切正常。 –