iT邦幫忙

2021 iThome 鐵人賽

DAY 27
0
Software Development

MongoDB披荊斬棘之路系列 第 27

DAY27 MongoDB Time Series Collection

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, minuteshours

建立 Time series collection

有著前面的知識後我們來準備一個範例,建立語法以及預設資料如下

db.createCollection("order.ts", {
  timeseries: {
    timeField: "orderDate",
    metaField: "customerName",
    granularity: "hours"
  },
    expireAfterSeconds: 3600*31*6 
});

資料範本

{
  "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

timeseries> show collections
order.ts                     [time-series]
system.buckets.order.ts
system.views

建立完後我們看到除了原本的 order.ts collection 有被標註為 [time-series],還多了兩個:

  • system.views
{
    "_id" : "timeseries.order.ts",
    "viewOn" : "system.buckets.order.ts",
    "pipeline" : [ 
        {
            "$_internalUnpackBucket" : {
                "timeField" : "orderDate",
                "metaField" : "customerName",
                "bucketMaxSpanSeconds" : 2592000,
                "exclude" : []
            }
        }
    ]
}

裡面存放了 bukets 的 view,與建立的資訊

  • system.buckets.order.ts

這裡總共有四筆資料,分別是按照 metaField 作為 group 統計而來的,礙於篇幅,我舉其中一個例子並分段來看

Part 1

{
    "_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

"meta" : {
    "lastName" : "Lee",
    "name" : "Bruce"
},

就是剛開始建立 Collection 時指定用來分群的 metaField

Part3

"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 集合。


本系列文章會同步發表於我個人的部落格 Pie Note


上一篇
DAY26 MongoDB 匯入與匯出資料
下一篇
DAY28 MongoDB Atlas 付費監控內容
系列文
MongoDB披荊斬棘之路30

尚未有邦友留言

立即登入留言