MongoDB规范化,外键和联接


68

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

我确实阅读了一些有关文档数据库的好处,并且我认为对于这个新应用程序,它们将非常有用。对许多类型的对象(很多M-M关系)和子类进行收藏,评论等总是很麻烦-处理起来很麻烦。

我也有一个结构,很难用SQL定义,因为它是非常嵌套的,并且可以比15个不同的表更好地转换为文档。

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

  1. 是否希望保持数据库正常化?我真的不想更新多个记录。人们还在用这种方式来处理MongoDB中的数据库设计吗?

  2. 当用户收藏一本书并且此选择仍存储在用户文档中但又删除该书时,会发生什么情况?没有外键如何分离关系?我自己负责删除所有链接吗?

  3. 如果用户偏爱一本已不存在的书并查询(某种连接),该怎么办?我必须在这里做任何容错吗?


当您使用MySQL这样的SQL数据库时,即使通过外键连接,它们也不会自动删除表之间的链接。他们唯一要做的就是阻止您删除通过外键连接的另一个表中的行,但是即使您告诉了它,也是如此。您为什么会认为NoSQL会有什么不同?
trysis 2014年

5
@ trysis,Google删除级联。
弗朗西斯·培根

2
是的,我忘记了为什么我这么说。如果我过去的无知误导了任何人,我深表歉意。
trysis

Answers:


65

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

仍然需要手动处理您的引用。仅当查找DBRef时,您才会看到它是否存在,如果引用的目标不再存在,DB将不会遍历所有文档来查找引用并删除它们。但是我认为删除本书后删除所有参考文献将只需要对每个集合进行一次查询,就不再需要了,所以实际上并不是那么困难。

如果您的模式更复杂,则可能应该选择关系数据库而不是nosql。

还有一本关于设计MongoDB数据库的书:MongoDB的文档设计

更新上面的书不再可用,但是由于MongoDB的流行,还有很多其他书。我不会链接所有链接,因为这样的链接很可能会更改,因此在Amazon上进行的简单搜索显示了多个页面,因此找到一些页面应该不是问题。

请参阅MongoDB手册页以获取“手册参考”和DBRef,以获取更多详细信息和示例


非常感谢您的回答!我实际上认为这个项目足够大,以至于Relational db现在是最佳选择。在此应用程序中,将有很多引用,并且在许多情况下将需要多个查询。这不值得。
egervari

1
帖子中提到的书在Amazon上不再可用。您知道这本书是否已被另一本书取代吗?
senfo 2011年

找到了这本书:shop.oreilly.com/product/0636920001096.do它可能包含有用的信息,以防与重新编辑的书不同。
Augustin Riedinger

不,不是:我提到的书是杰里米·麦卡纳利(Jeremy McAnally)和瑞安·尼兹(Ryan Nitz)所著,克里斯蒂娜·科多罗(Kristina Chodorow)则为您所著。从那时起,实际上MongoDB有了很大的发展,并且有很多书籍可供使用,仅O'Reilly就有6本书,在亚马逊上的简单搜索显示了多页,这对于仍然可以在纸上阅读的人们来说是一种舒适的情况:-) ..
Tomasz Stanczak

24

上面,@ TomaaszStanczak指出

MongoDB不支持服务器端外键关系,也不鼓励进行规范化。如果可能,您应该将子对象嵌入父对象中,这将提高性能并完全不需要外键。但这并不总是可能的...

Mongo不建议规范化。明确地说,我们正在谈论两个数据实体可以具有的两种根本不同类型的关系。一个拥有一个子实体实例中仅由父对象。在这种类型的关系中,将嵌入Mongo方式。

在另一类关系中,两个实体独立存在-具有独立的生存期和关系。Mongo希望这种关系不存在,并且对如何处理这种关系感到沮丧而沉默。嵌入并不是解决方案。不鼓励或不鼓励进行规范化。Mongo只是为您提供了两种处理它的机制。手动refs(类似于具有绑定到两个表的外键约束的键)和 DBRef(一种不同的,略微结构化的相同方法)。在这种情况下,SQL数据库将获胜。


3
+1同意。互联网上经常出现这样的引用:“通常来说,在MongoDB中,您希望以应用程序访问数据的方式存储数据,从而消除了连接的需要”,但是关于专有所有权和推断的稳定性的观点很常见。数据经常被忽略。
理查德·EB

1

Tomasz和Francis的答案都包含很好的建议:Mongo不鼓励“规范化”,但是在创建“文档引用”之前,您应该首先考虑优化数据库文档设计。 DBRefsTomasz提到的这些,但是,正如他所指,并不是“魔术子弹”,需要进行额外的处理才有用。

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

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

至于孤立的文档,从您的问题来看,我想您是在考虑传统的RDBMS约束集,级联删除等。同样,从MongoDB 3.2版开始,对文档验证提供了本机支持。看一下这篇StackOver文章:如何在MongoDB中应用约束? 看第二个答案,来自JohnnyHK

Packt出版商在MongoDB上有一堆好书。(完全披露:我写了几张。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.