如何在MongoDB中有效地更新时间序列数据

时间:2017-09-12 05:12:22

标签: node.js mongodb

我在mongodb中有以下时间序列数据

频道收集包含有关每个频道的数据。 每个频道文档都有实时数据 - > rtData是一个json数组,用于保存该通道的时间序列数据。

db.channels.find({})。pretty()给出了类似的结构

  {
    channelName:"ABC",
    rtData:[
      {
        ts:ISO_DATE(timestamp),
        data:[12, 14]
      },
      {
        ts:ISO_DATE(timestamp),
        data:[12, 14]
      },
      {
        ts:ISO_DATE(timestamp),
        data:[12, 14]
      },
      .
      .
      .
  },
  {
    channelName:"NBC",
    rtData:[
      {
        ts:ISO_DATE(timestamp),
        data:[12, 14]
      },
      {
        ts:ISO_DATE(timestamp),
        data:[12, 14]
      },
      {
        ts:ISO_DATE(timestamp),
        data:[12, 14]
      },
      .
      .
      .
  },

现在,我每4秒钟获得一个或多个频道的更新记录

{
  ts: ISO_DATE(timestamp),
  data: [14,15]
}

我需要在该频道的rtData数组中推送/更新此记录。

所以我所做的与此类似 -

channels.findOne({query}, function(channel) {
  channel.rtData.push(newData);

  channels.findAndModify({query}, {$set:{rtData: channel.rtData}}, 
    function({}))
})

找到频道,将数据推送到rtData数组并进行查找和修改。

现在,当数据量很低时,这似乎有效。但是当一个单一通道的rtData数组中有近50K元素时,应用程序无法处理。

是否有效更新时间序列数据。

1 个答案:

答案 0 :(得分:1)

你已经过了你的模型,imho。请记住,MongoDB中的BSON文档有16MB的大小限制。 此外,修改文档比简单地插入文档需要花费更多的时间。

由于ObjectID contains a timestamp already并且还为每个输入的值提供了唯一性,例如

{
   _id: new ObjectID(),
   channelName: "NBC",
   value: [14,15]
 }

使插入数据非常有效。对于基于日期的查询,您可以利用ObjectIDs以包含自纪元以来的秒数的4字节值的十六进制表示开始,并且以其他方式单调增加:

secs = Math.floor(Date.Now()/1000)
hexSecs = secs.toString(16)
id = ObjectId(hexSecs+"0000000000000000")

db.values.find({"_id":{$lt:id}})

此示例将为您提供所有早于调用时间Date.Now()的条目。当然,您可以使用转换开始日期和结束日期的相同方法查询范围。有关更详细的说明,请参阅the according entry "Popping time stamps into ObjectIds" on Kristina Chodorow's blog

其余的查询和聚合应该是显而易见的。