【问题标题】:MongoDB normalization, foreign key and joiningMongoDB规范化,外键和加入
【发布时间】:2011-08-16 01:09:41
【问题描述】:

在我真正深入研究 MongoDB 几天之前,我想我会问一个非常基本的问题,即我是否应该深入研究它。我基本上没有使用nosql的经验。

我确实阅读了一些关于文档数据库的一些好处,我认为对于这个新应用程序来说,它们会非常棒。为许多类型的对象(许多 m-to-m 关系)和子类做 favourites、cmets 等总是很麻烦 - 处理起来有点痛苦。

我还有一个结构在 SQL 中定义会很痛苦,因为它非常嵌套,并且比 15 个不同的表更好地转换为文档。

但我对一些事情感到困惑。

  1. 是否仍需要保持数据库标准化?我真的不想更新多条记录。这仍然是人们在 MongoDB 中设计数据库的方式吗?

  2. 如果用户收藏了一本书,并且此选择仍存储在用户文档中,但随后该书被删除,会发生什么情况?如果没有外键,关系如何分离?我是否要亲自负责删除所有链接?

  3. 如果用户收藏了一本不再存在的书并且我查询它(某种连接),会发生什么情况?我必须在这里做任何容错吗?

【问题讨论】:

  • 当你做像 MySQL 这样的 SQL 数据库时,它们不会自动删除表之间的链接,即使通过外键连接也是如此。他们唯一做的就是阻止你删除另一个通过外键连接的表中的一行,但即使在那里也只有你告诉它。为什么你会认为在 NoSQL 中会有所不同?
  • @trysis,谷歌删除级联。
  • 是的,我忘了我为什么这么说,那是很久以前的事了。如果我因过去的无知而误导了任何人,我深表歉意。

标签: mongodb foreign-keys normalization database nosql


【解决方案1】:

Tomasz 和 Francis 的回答都包含很好的建议:Mongo 并不反对“规范化”,但您应该首先考虑在创建“文档引用”之前优化您的数据库文档设计。 Tomasz 提到了DBRefs,但正如他所暗示的那样,它不是“灵丹妙药”,需要额外的处理才能发挥作用。

从 MongoDB 版本 3.2 开始,现在可以通过使用 $lookup 聚合管道阶段运算符生成与 SQL JOIN 等效的结果。通过这种方式,您可以拥有“规范化”的文档结构,但仍然能够产生合并的结果。为了让它工作,你需要在目标集合中创建一个唯一的键,希望它既有意义唯一。您可以通过在此字段上创建唯一索引来强制唯一性。

$lookup 的使用非常简单。在此处查看文档:https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/#lookup-aggregation。在源集合(即“左”表)上运行 aggregate() 方法。 from 参数是目标集合(即“右”表)。 localField 参数将是源集合中的字段(即“外键”)。 foreignField 参数将是目标集合中的匹配字段。

就孤立文档而言,根据您的问题,我假设您正在考虑一组传统的 RDBMS 约束、级联删除等。同样,从 MongoDB 版本 3.2 开始,对 文档验证。看看这篇 StackOver 文章:How to apply constraints in MongoDB? 看看第二个答案,来自 JohnnyHK

Packt Publishers 有很多关于 MongoDB 的好书。 (完全披露:我写了几个。)

【讨论】:

    【解决方案2】:

    MongoDB 不支持服务器端外键关系,也不鼓励规范化。如果可能,您应该将您的子对象嵌入到父对象中,这将提高性能并使外键完全没有必要。也就是说,这并不总是可能的,因此有一个称为 DBRef 的特殊构造,它允许引用不同集合中的对象。这可能不会那么快,因为 DB 必须进行额外的查询才能读取对象,但允许某种外键引用。

    您仍然必须手动处理您的参考资料。只有在查找您的 DBRef 时,您才会看到它是否存在,如果引用的目标不再存在,DB 将不会遍历所有文档来查找引用并删除它们。但我认为删除这本书后删除所有引用将需要每个集合一个查询,仅此而已,所以真的没那么难。

    如果您的架构更复杂,那么您可能应该选择关系数据库而不是 nosql。

    还有一本关于设计MongoDB数据库的书:Document Design for MongoDB

    更新 上面的书已经没有了,但是由于 MongoDB 的流行,还有很多其他的。我不会将它们全部链接起来,因为这些链接可能会发生变化,在亚马逊上进行简单搜索会显示多个页面,因此找到一些应该不是问题。

    有关详细信息和示例,请参阅'Manual references' and DBRefs 的 MongoDB 手册页

    【讨论】:

    • 非常感谢您的回答!我实际上认为这个项目足够大,关系数据库是现在最好的选择。在这个应用程序中,会有很多引用,并且在很多情况下会进行多次查询。这不值得。
    • 帖子中提到的这本书在亚马逊上不再可用。你知道这本书是否被另一本书取代了吗?
    • 找到了这个:shop.oreilly.com/product/0636920001096.do 它可能包含有用的信息,以防它不是重新编辑的同一本书。
    • 不,不是:我提到的这本书是 Jeremy McAnally 和 Ryan Nitz 写的,而你的则是 Kristina Chodorow。实际上,从那时起 MongoDB 发展势头非常强劲,有很多书籍可供选择,仅 O'Reilly 就有 6 本书,在 Amazon 上进行简单搜索会显示多个页面,对于那些仍然可以在纸上阅读的人来说,这是一个舒适的情况 :-)..
    【解决方案3】:

    以上,@TomaaszStanczak 状态

    MongoDB 不支持服务器端外键关系, 也不鼓励标准化。你应该嵌入你的子对象 如果可能的话,在父对象中,这将提高性能和 使外键完全没有必要。也就是说并不总是 可能...

    Mongo 并不反对规范化。为了清楚起见,我们谈论的是两个数据实体可以拥有的两种根本不同类型的关系。一种情况是,一个子实体拥有由一个父对象独占。在这种类型的关系中,Mongo 的方式是嵌入。

    在另一类关系中,两个实体独立存在 - 具有独立的生命周期和关系。 Mongo 希望这种类型的关系不存在,但令人沮丧的是,他对如何处理它保持沉默。嵌入不是解决方案。不鼓励或鼓励规范化。 Mongo 只是给你两种机制来处理它; Manual refs(类似于具有绑定两个表的外键约束的键)和DBRef(一种不同的,稍微结构化的方法)。在这个用例中,SQL 数据库获胜。

    【讨论】:

    • +1 同意。像“一般来说,在 MongoDB 中,您希望以应用程序访问数据的方式存储数据,从而消除连接的需要”在互联网上的引用很常见,但您对独占所有权和推断的稳定性的观点数据经常被忽视。
    猜你喜欢
    • 2012-01-11
    • 2012-08-10
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多