2016-01-24 56 views
0

在我看來,有兩種方法可以在MongoDB中實現多對多關係,規範化或非規範化,兩者都有折衷。我如何決定實施哪種模式?本OP的其餘部分用示例解釋了權衡。MongoDB:多對多 - 什麼時候執行非規範化vs規範化?

產品與Sku的關係。一個產品有許多skus,每個sku可能與許多產品相關聯。 (我不打算這個問題的答案是特定於這個例子,而是任意的多對多關係)。

在一個標準化的模型中,有兩個集合,產品和SKU。兩個集合中的每個Document均包含一個指向其他集合的(對象)ID數組。

優點:

  • 數據不重複
  • 防止更新/插入/缺失的異常
  • 查找的SKU的不同列表(除了外鍵陣列)並不昂貴

缺點:

  • M兩個單獨文檔的差異不是原子的
  • 查找給定產品的skus或相反,需要對數據庫進行兩次查詢。
  • 外鍵並不強制,但貸款是自我異常(但僅限於外鍵陣列)

例如,

db.store.sku.insert({ 
    'sku_id': 1, 
    'name': 'cheese', 
    'price': 0.50, 
    'products': [10] 
}) 
db.store.sku.insert({ 
    'sku_id': 2, 
    'name': 'beef paddy', 
    'price': 0.25, 
    'products': [10] 
}) 
db.store.product.insert({ 
    'product_id': 10, 
    'name': 'cheese burger', 
    'skus': [1, 2] 
}); 
db.store.product.insert({ 
    'product_id': 11, 
    'name': 'hamburger', 
    'skus': [2] 
}); 

規格化

在非規範化的模式,有一個集合。集合中的每個文檔都包含一組文檔。

優點:

  • 修改到單個文檔是原子
  • 查找的SKU對於給定的產品,或者相反,僅需要一個查詢到的分貝。

缺點:

  • 數據被複制
  • 適合於更新/插入/缺失距平
  • 找到單品的獨特名單是昂貴的(我假設是db.store.product .distinct(skus)相對較貴)

eg,

db.store.product.insert({ 
    'product_id': 10, 
    'name': 'cheese burger', 
    'skus': [ 
     { 
      'sku_id': 1, 
      'name': 'cheese', 
      'price': 0.50, 
     }, 
     { 
      'sku_id': 2, 
      'name': 'beef paddy', 
      'price': 0.25, 
     } 
    ] 
}); 
db.store.product.insert({ 
    'product_id': 11, 
    'name': 'hamburger', 
    'skus': [ 
     { 
      'sku_id': 2, 
      'name': 'beef paddy', 
      'price': 0.25, 
     } 
    ] 
}); 

要注意,有一些混合動力車型,其中最常被查詢的屬性和/或至少有可能改變的屬性存儲在非規範化的集合中,而所有其他屬性都存儲在這將是重要的一個參考集合。

如何決定在MongoDB中實現多對多關係的方法?

回答

0

我認爲你所說的「非規範化」對於你的問題範圍來說顯然是錯誤的,因爲你正在存儲與數據結構中不相關的不同但等價的「sku」子文檔。有兩個不同的「sku_id」:2個字段就好了,就像兩篇博文都可以有不同的用戶發表第一條評論,但在你的情況下它不是。如果您在數據模型中允許使用錯誤狀態,那麼即使在您開始之前,您也會遇到嚴重問題

您的「標準化」方法更好,但對於您的方案仍然不正確。您的數據建模意味着產品和SKU之間的關係(以圖表形式)是一個有向邊緣,這意味着產品可以引用SKU而無需SKU返回產品。

我能想到兩種正確的建模方法:您可以參考產品中的SKU,只是沒有參考返回,因爲它隱含在那裏。如果你需要一種從SKU到產品清單的方式,我建議建立一個查詢並且可能是一個索引,但是請不要把這個鏈接加倍連接。第二種方法是SQL n:m方法:擁有一組僅包含關係信息的文檔。但說實話,我認爲除非你在產品和SKU之間的這種聯繫上進行一些非常嚴肅的操作,否則這將是一件壞事,因爲它是正確的。

哦,對於外鍵約束:在MongoDB中沒有這樣的事情。因爲沒有模式定義,所以甚至沒有可以定義這種事情的地方。