MongoDB Advanced Schema Design Pattern - Single Collection Pattern

用一句簡單的話說

所有不同類型的資料存入同一個 collection,以簡化查詢與索引策略。


場景

拿 Book, User, Review 的例子來說,這三者常常會被一起 Query,儲存資料的結構可能是

  1. 存在不同 collection 中 → 經常需要 $lookup
  2. 存在同個 document 中 → 容易超過 16M 大小限制

這時可以考慮 Single Collection Pattern,透過將資料存在同個 collection 來避免上述的困境,主要有兩個 variant


Variant 1

  1. 可用於一對多多對多
  2. Array of references → 建立 index (下面例子中的 relatedTo field)
  3. docType field → inheritance pattern 的應用

舉例來說,將同一本書的 review, user, book 所有 documents 存在同一個 collection

{
review_id: '',
docType: "review",
relatedTo: [10] // 指向 book_id
}
{
user_id: "",
docType: "user",
relatedTo: [10] // 指向 book_id
}
{
book_id: 10,
docType: "book",
relatedTo: [10] // 指向自己
}

會用 relatedTo 來找這些資料,所以建立 index

db.books_catalog.createIndex({ relatedTo: 1 })

接著就可以用 book id 去 query 到這些 documents

// 找所有的 documents
db.books_catalog.find({ relatedTo: 10 })

// 找特定 docType 的 documents
db.books_catalog.find({ relatedTo: 10, docType: "review" })

Variant2

  1. 只能使用一對多
  2. Overloaded field (下例的 sc_id),多功能的 field
    • 用來找到對應的 field
    • 用來加強 query 效能

{
book_id: 10,
sc_id: 10
}
{
review_id: 123,
sc_id: '10/123'
}

一樣建立 index

db.books_catalog.createIndex({ sc_id: 1 })

先找到所有以 book_id 開頭的 documents (包含 book 及該 book 底下的所有 reviews )

db.books_catalog.find({ "sc_id": { '$regex': "^10" }})

query 條件加上 / 過濾掉 book, 只留下 review 本身

db.books_catalog.find({ "sc_id": { '$regex': "^10/" }})