2021 iThome 鐵人賽 MongoDB披荊斬棘之路
DAY27 MongoDB Time Series Collection
什麼是 Time series collection
MongoDB 5.0 發佈的新功能,僅在 5.0 之後的版本提供。
時間序列集合(Time series collection) 是一個新型態的集合,有別於 capped collection
與 一般 Collection
,它有諸多限制:
- 僅支援 Read / Insert
- 無法 Delete / Update,只能夠
drop collection
- document 最大 4MB
- 無法轉為
capped
或 一般
collection,反之亦然
- 沒辦法設定 Index 的
unique
(_id為例外), partial
metaField
, timeField
(後面說明)兩欄位僅有在建立 Collection 才可以決定,之後無法修改。
- Collection 無法 sharding
看了這麼多限制後,還是不知道什麼是時間序列集合。基本上該功能就可以想像成依照時間來進行統計分析的集合,像是股票資料或天氣資料這種,依照時間進行,然後去統計分析股票價位高低或者溫度的高低。
Time series collection 三大設定
timeField
時間欄位,指定要做為統計的時間欄位,必須是要時間的資料型別
metaField
分群的欄位,統計資料會自動以該欄位進行分群。
因為只能指定一個欄位,所以可以進行變通,例如原本是 { "name": "Bruce"}
改為 { "name": "Bruce", "lastName": "Lee" }
granularity
統計時間粒度,可以是 seconds
, minutes
或 hours
建立 Time series collection
有著前面的知識後我們來準備一個範例,建立語法以及預設資料如下
1 2 3 4 5 6 7 8
| db.createCollection("order.ts", { timeseries: { timeField: "orderDate", metaField: "customerName", granularity: "hours" }, expireAfterSeconds: 3600*31*6 });
|
資料範本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| { "customerId": 10001, "customerName": { "name":"Bruce", "lastName": "Lee" }, "orderPrize": 1280, "orderStatus": 1, "orderDate": ISODate("2021-09-01T11:00:00.000Z"), "deliverDate": ISODate("2021-09-05T15:00:00.000Z") }, { "customerId": 10001, "customerName": { "name":"Bruce", "lastName": "Lee" }, "orderPrize": 1880, "orderStatus": 3, "orderDate": ISODate("2021-09-01T12:00:00.000Z"), "deliverDate": ISODate("2021-09-06T16:00:00.000Z") }, { "customerId": 10001, "customerName": { "name":"Bruce", "lastName": "Lee" }, "orderPrize": 540, "orderStatus": 2, "orderDate": ISODate("2021-09-02T03:00:00.000Z"), "deliverDate": ISODate("2021-09-07T17:00:00.000Z") }, { "customerId": 10002, "customerName": { "name":"Old", "lastName": "Chou" }, "orderPrize": 2300, "orderStatus": 1, "orderDate": ISODate("2021-09-01T10:00:00.000Z"), "deliverDate": ISODate("2021-09-07T14:00:00.000Z") }, { "customerId": 10003, "customerName": "Kate", "orderPrize": 2890, "orderStatus": 3, "orderDate": ISODate("2021-09-01T12:00:00.000Z"), "deliverDate": ISODate("2021-09-07T14:00:00.000Z") }
|
查看 time series collection
1 2 3 4
| timeseries> show collections order.ts [time-series] system.buckets.order.ts system.views
|
建立完後我們看到除了原本的 order.ts
collection 有被標註為 [time-series]
,還多了兩個:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| { "_id" : "timeseries.order.ts", "viewOn" : "system.buckets.order.ts", "pipeline" : [ { "$_internalUnpackBucket" : { "timeField" : "orderDate", "metaField" : "customerName", "bucketMaxSpanSeconds" : 2592000, "exclude" : [] } } ] }
|
裡面存放了 bukets 的 view,與建立的資訊
這裡總共有四筆資料,分別是按照 metaField
作為 group
統計而來的,礙於篇幅,我舉其中一個例子並分段來看
Part 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| { "_id" : ObjectId("612ec2808b826f0fc8ce4afa"), "control" : { "version" : 1, "min" : { "_id" : ObjectId("614eee10ebdbba2a6c81adbd"), "customerId" : 10001.0, "orderPrize" : 540.0, "orderStatus" : 1.0, "orderDate" : ISODate("2021-09-01T00:00:00.000Z"), "deliverDate" : ISODate("2021-09-05T15:00:00.000Z") }, "max" : { "_id" : ObjectId("614eee10ebdbba2a6c81adbf"), "customerId" : 10001.0, "orderPrize" : 1880.0, "orderStatus" : 3.0, "orderDate" : ISODate("2021-09-02T03:00:00.000Z"), "deliverDate" : ISODate("2021-09-07T17:00:00.000Z") } },
|
這邊直接幫你算出 metaField { "name":"Bruce", "lastName": "Lee" }
分類裡的每個項目的最小值與最大值,要是能設定多算一些統計值也是不錯吧。
有個小疑問是最小值的 orderDate 值是 ISODate("2021-09-01T00:00:00.000Z")
但原始數據明明是 ISODate("2021-09-01T10:00:00.000Z")
,可能會是個 bug?
Part 2
1 2 3 4
| "meta" : { "lastName" : "Lee", "name" : "Bruce" },
|
就是剛開始建立 Collection 時指定用來分群的 metaField
Part3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| "data" : { "orderDate" : { "0" : ISODate("2021-09-01T11:00:00.000Z"), "1" : ISODate("2021-09-01T12:00:00.000Z"), "2" : ISODate("2021-09-02T03:00:00.000Z") }, "customerId" : { "0" : 10001.0, "1" : 10001.0, "2" : 10001.0 }, "deliverDate" : { "0" : ISODate("2021-09-05T15:00:00.000Z"), "1" : ISODate("2021-09-06T16:00:00.000Z"), "2" : ISODate("2021-09-07T17:00:00.000Z") }, "orderPrize" : { "0" : 1280.0, "1" : 1880.0, "2" : 540.0 }, "_id" : { "0" : ObjectId("614eee10ebdbba2a6c81adbd"), "1" : ObjectId("614eee10ebdbba2a6c81adbe"), "2" : ObjectId("614eee10ebdbba2a6c81adbf") }, "orderStatus" : { "0" : 1.0, "1" : 3.0, "2" : 2.0 } }
|
從這邊可以看到 data
這個項目裡面存放的就是各個欄位的原始數據,如果要做聚合、統計都能夠從這邊直接取用,順序也是按照寫入的順序。
看到這邊我就不再繼續延伸使用 aggregation
示範內容了,基本上 time series collection
就是幫你把資料按照另一個格式進行儲存,讓你可以更快的在感興趣的欄位進行統計。
另外因為是 demo 概念,沒有建立 index,請務必在使用時加上相對應得索引,使你的查詢更加有效率。
例如幫你自動分桶的集合 system.buckets.order.ts
能這樣做,或者是原本的 order.ts
集合。