【问题标题】:MongoDB - What is the fastest way to get the latest value as-of a given date?MongoDB - 获取给定日期的最新值的最快方法是什么?
【发布时间】:2015-12-07 02:28:45
【问题描述】:

我收集了来自不同来源、不同频率的测量结果。

对于任何给定的来源子集,我如何获得截至特定日期的最新良好价值? (这类似于pandas.Index.asof)?

需要明确的是,对于其中一些时间序列可能没有所需日期的可用值,因此我必须在可用日期中找到低于查询日期的最新日期。

时间序列可能如下所示:

{_id:new ObjectId(), source:"1stDayofMonth", date:new ISODate(<day1>) value:somevalue}
{_id:new ObjectId(), source:"Monday", date:new ISODate(<day1>) value:somevalue}
{_id:new ObjectId(), source:"daily", date:new ISODate(<day1>) value:somevalue}
/...
{_id:new ObjectId(), source:"daily", date:new ISODate(<dayN>) value:somevalue}
{_id:new ObjectId(), source:"Wednesday", date:new ISODate(<dayN>) value:somevalue}
// and so on... 

给定正确的索引 (db.myCollection.createIndex({date:1, source:1})),对于sources 的任何子集,我如何才能获得给定queryDate 的最新良好value

这是我得到的结果,但这个解决方案未能返回每个 source 的 1 个 value(如果您阅读代码,您会发现仅查询一个 source 时这会起作用,但是当查询不同的,它返回超过 1 个高频源值):

querySources = ['1stDayofMonth','Monday']    # as an example, let's say I want only these 2 sources
nSources = np.size(querySources)
cursor = db.myCollection.find( {'source':{ '$in': querySources}, 'date':{ '$lt': queryDate}}).sort(date:-1).limit(nSources)

有什么想法吗?

编辑:我应该提到文档指出this solution,但aggregate 可能非常慢并且集合足够大以至于查询时间变长(例如查询 1000 个源,每个源有 10000 天的数据)

【问题讨论】:

    标签: mongodb pymongo


    【解决方案1】:

    为了记录,我找到了一种方法,通过在文档中添加 1 个字段来覆盖查找:

    如果我为每个文档添加一个“nextDate”字段,其中包含该系列的下一个连续文档的日期,那么我可以对最大速度进行覆盖查询:

    find( {'ind':{$in:[<sources>]},'date':{'$lte':queryDate}, 'nextDate':{'$gt':queryDate}},
          {'_id':0, 'nextDate':0} ).hint('my_index')
    

    myindex 基于inddatenextDatevalue

    占用大量空间和内存,非常快

    【讨论】:

      【解决方案2】:

      您得到的结果不止一个,因为nSources 的大小大于 1。

      如果您想按来源分组,您必须使用aggregate,或者您必须为每个来源运行一个find(),然后加入结果。

      使用aggregate的解决方案:

      db.myCollection.aggregate([
      {$match : {source: {$in: ["1stDayofMonth", "Monday"]}}},
      {$match : {date: {$lt: queryDate}}},
      {$sort : { date : -1 } },
      {$group : {
          _id : "$source",
          date : {"$first" : "$date"},
          value : {"$first" : "$value"}   
          }}
      ])
      

      使用find()的解决方案:

      curs1 = db.myCollection.find( {'source': "1stDayofMonth", 
      'date':{ '$lt': queryDate}})
      .sort({date:-1}).limit(1);
      
      curs2 = db.myCollection.find( {'source': "Monday", 
      'date':{ '$lt': queryDate}})
      .sort({date:-1}).limit(1);
      
      # Now add the result from each cursor to an Array in your app
      

      【讨论】:

      • 谢谢,nSources 在那里,因为我想得到一个答案每个成员 querySources 列表
      • 我就是这么想的。它不是那样工作的。您实际上是在说“限制查询源大小的所有记录”,因为您的 .find() 无法对 $in 语句进行分组。
      • 谢谢,我认为你是对的。我希望做 1 find 只是为了加快速度并避免聚合,但是在我添加一些其他要排序的排名字段之前,这将不起作用。谢谢
      猜你喜欢
      • 2014-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-28
      • 2012-12-29
      • 2019-12-10
      • 2023-03-30
      • 1970-01-01
      相关资源
      最近更新 更多