用一句簡單的話說 Inheritance Pattern 幫助在同一個 collection 中管理擁有類似但不同結構的 document。
場景 在 MongoDB 中,同一個集合(Collection)內的不同文檔(Document)可以具有不同的結構稱作 Polymorphism (多態性),即使它們存儲的數據類型不同,但仍然可以在同一個集合中共存並進行查詢和操作。
而在儲存資料的時候經常因為黃金守則:data that is accessed together should be stored together
的緣故,這些不同結構的 documents 常被儲存在同一個 collection,而當這些 document 的 schema 大部分的 field 是相同的時候就可以考慮使用 inheritance pattern 來管理。
inheritance pattern 利用 document 裡的某個 field 來表示自己屬於哪一種結構,例如一個 posts collection 中有三種不同類型的 document。
{ "_id" : ObjectId ("1" ), "type" : "text" , "title" : "MongoDB Polymorphism" , "created_at" : "2024-03-08" , "text" : "MongoDB polymorphism refers to..." } { "_id" : ObjectId ("2" ), "type" : "image" , "title" : "風景圖片" , "created_at" : "2024-07-04" , "image_url" : "https://example.com/image.jpg" } { "_id" : ObjectId ("3" ), "type" : "video" , "title" : "MongoDB 教學影片" , "created_at" : "2024-09-23" , "video_url" : "https://example.com/video.mp4" }
利用 type field 來表示自己屬於哪一種類型的文章: 純文字類型的文章 type 為 text
並且有 text
這個 field 圖片文章 type 為 image
並有 image_url
這個 field 影片文章 type 為 video
並有 video_url
這個 field
如此一來,即便同一個 collection 可能有不同的 document,在 query 的時候就能藉由 type 知道這個 document 有哪一些 field 並做出對應的邏輯處理。
改變現有的 schema 有個很常見的狀況是,隨著產品推演經常會遇到 schema 設計與原本不同的狀況,以這個例子來說一開始可能只預設會有純文字的文章,而後來增加了圖片與影片文章,這時的原始資料就不會有 type。
{ "_id" : ObjectId ("1" ), "title" : "MongoDB Polymorphism" , "created_at" : "2024-03-08" , "text" : "MongoDB polymorphism refers to..." } { "_id" : ObjectId ("2" ), "title" : "風景圖片" , "created_at" : "2024-07-04" , "image_url" : "https://example.com/image.jpg" } { "_id" : ObjectId ("3" ), "title" : "MongoDB 教學影片" , "created_at" : "2024-09-23" , "video_url" : "https://example.com/video.mp4" }
可以利用以下的 aggregation pipeline 來做資料的轉換
$match
找到不同 type 對應的 field
$set
對這些 documents 指定 type
$merge
更新原有的 documents
const set_text_type_pipeline = [ { $match : { text : { $exists : true } }, }, { $set : { type : "text" }, }, { $merge : { into : "posts" , on : "_id" , whenMatched : "replace" , whenNotMatched : "discard" , }, }, ]; const set_image_type_pipeline = [ { $match : { 'image_url' : { $exists : true } }, }, { $set : { type : "image" }, }, { $merge : { into : "posts" , on : "_id" , whenMatched : "replace" , whenNotMatched : "discard" , }, }, ]; const set_image_type_pipeline = [ { $match : { 'video_url' : { $exists : true } }, }, { $set : { type : "video" }, }, { $merge : { into : "posts" , on : "_id" , whenMatched : "replace" , whenNotMatched : "discard" , }, }, ];
影片說明 (en)
VIDEO