MongoDB:多对多 - 何时实现非规范化与规范化?

时间:2016-01-24 20:27:08

标签: mongodb

在我看来,有两种方法可以在MongoDB中实现多对多关系,规范化或非规范化,两者都有权衡。如何确定要实施哪种模型?本OP的其余部分用例子解释了权衡。

将产品带到Sku关系。一种产品有许多skus,每个sku可能与许多产品相关联。 (我不打算将这个问题的答案特定于这个例子,而是任意多对多关系)。

归一化的

在标准化模型中,有两个集合,product和sku。两个集合中的每个Document都包含一个指向另一个集合的(对象)id数组。

优点:

  • 数据不重复
  • 防止更新/插入/删除异常(外键数组除外)
  • 查找不同的skus列表并不昂贵

缺点:

  • 对两个单独文档的修改不是原子的
  • 查找给定产品的skus,或相反,需要向DB提出两个查询。
  • 外部密钥未强制执行,将其自行处理为异常(但仅限于外键数组)

如,

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]
});

规格化

在非规范化模型中,有一个集合。集合中的每个文档都包含一系列文档。

优点:

  • 对单个文档的修改是原子的
  • 查找给定产品的skus,或者相反,只需要对db进行一次查询。

缺点:

  • 数据重复
  • 适合更新/插入/删除异常
  • 查找一个独特的skus列表很昂贵(我假设db.store.product.distinct(skus)相对昂贵)

,例如,

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中实现多对多关系的方法?

1 个答案:

答案 0 :(得分:0)

我认为您所谓的“非规范化”对于您的问题范围来说是完全错误的,因为您存储的是与数据结构无关的不同但等效的“sku”子文档。有两个不同的“sku_id”:2个字段就可以了,就像两个博客帖子都可以有不同用户的“第一”评论,但在你的场景中却没有。如果您在数据模型中允许破坏状态,那么即使在开始之前,您也会遇到严重问题。

您的“规范化”方法更好,但仍然不适合您的方案。您的数据建模意味着产品和SKU之间的关系(在图表方面)是有针对性的边缘,这意味着产品可以在没有SKU参考产品的情况下引用SKU。

我可以想到两种正确的建模方法:要么你只是引用产品中的SKU而只是没有引用,因为它隐含在那里。如果您需要从SKU到产品列表的方法,我建议构建一个查询,可能还有一个索引,但请不要双重链接。第二种方法是SQL n:m方法:拥有一组仅包含有关此关系的信息的文档。但说实话,我认为除非你在产品和SKU之间的这种联系上运行一些非常严肃的操作,否则这将是正确的。

哦,对于外键约束:MongoDB中没有这样的东西。甚至没有一个地方可以定义这样的东西,因为没有模式定义。