2017-12-18 170 views
1

我對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分「?

回答

0

有從你給的是應該指向你在正確的方向的鏈接@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'階段在第一天/最後一天過濾掉不想要的值。總的來說,變得相當複雜,我想要在生產大小的數據集上運行測試,以確保查詢性能一切正常。 –