在我深入MongoDB几天之前,我想我会问一个非常基本的问题,我是否应该深入研究它。我基本上没有使用nosql的经验。
我确实读过一些关于文档数据库的一些好处,我认为对于这个新的应用程序,它们会非常棒。对于许多类型的对象(许多m-to-m关系)和子类来说,做收藏夹,评论等总是很麻烦 - 这是一种很难处理的问题。
我还有一个在SQL中定义很难的结构,因为它非常嵌套并且比15个不同的表更好地转换为文档。
但我对一些事感到困惑。
是否仍需要保持数据库规范化?我真的不想更新多条记录。这仍然是人们如何处理MongoDB中数据库的设计?
当用户收藏图书并且此选择仍存储在用户文档中,但该图书被删除后会发生什么?没有外键,关系如何分离?我自己负责删除所有链接吗?
如果用户喜欢不再存在的图书并且我查询它(某种类型的加入),会发生什么?我必须在这里做任何容错吗?
答案 0 :(得分:63)
MongoDB不支持服务器端外键关系,也不鼓励规范化。如果可能,您应该将子对象嵌入父对象中,这将提高性能并使外键完全不必要。也就是说它并不总是可行的,所以有一个名为DBRef的特殊构造允许引用不同集合中的对象。这可能不那么快,因为DB必须进行额外的查询才能读取对象,但允许进行外键引用。
仍然需要手动处理您的参考。只有在查找DBRef时,您才会看到它是否存在,如果引用的目标不再存在,DB将不会遍历所有文档以查找引用并删除它们。但我认为删除书后删除所有引用都需要每个集合只有一个查询,不再需要,所以不是那么困难。
如果您的架构更复杂,那么您可能应该选择关系数据库而不是nosql。
还有一本关于设计MongoDB数据库的书:Document Design for MongoDB
更新上面的书已不再可用,但由于MongoDB的普及,还有很多其他的。我不会将它们全部链接起来,因为这样的链接可能会改变,亚马逊上的简单搜索会显示多个页面,因此查找一些页面应该不会有问题。
有关更多细节和示例,请参阅MongoDB手册页'Manual references' and DBRefs
答案 1 :(得分:18)
上图,@ TomaaszStanczak声明
MongoDB不支持服务器端外键关系, 也不鼓励正常化。你应该嵌入你的孩子对象 如果可能,在父对象内,这将提高性能和 完全没必要使用外键。这说并不总是 可能......
Mongo不鼓励标准化。为了清楚起见,我们讨论的是两个数据实体可以拥有的两种根本不同的关系类型。在一个中,一个子实体仅由父对象拥有。在这种关系中,Mongo的方式是嵌入。
在另一类关系中,两个实体独立存在 - 具有独立的生命周期和关系。 Mongo希望这种关系不存在,并且对于如何处理这种关系感到沮丧。嵌入不是解决方案。不鼓励或鼓励标准化。 Mongo只给你两种机制来处理它; Manual refs(类似于绑定两个表的外键约束的键)和DBRef(一种不同的,稍微更结构化的方式)。在这个用例中,SQL数据库获胜。
答案 2 :(得分:0)
Tomasz和Francis的答案都包含很好的建议:Mongo不鼓励“规范化”,但是在创建“文档引用”之前,您应该首先考虑优化数据库文档设计。 DBRefs
是Tomasz提到的,但是正如他所暗示的那样,它不是“魔术子弹”,需要进行其他处理才有用。
从MongoDB 3.2版开始,现在可以使用 $ lookup 聚合管道阶段运算符来产生与SQL JOIN 等效的结果。通过这种方式,您可以具有“规范化”的文档结构,但仍然能够产生合并的结果。为了使它起作用,您需要在目标集合中创建一个唯一的键,希望它既是有意义的又是 unique 。您可以通过在此字段上创建唯一索引来强制唯一性。
$ lookup 用法非常简单。在这里查看文档:{{3}}。在源集合(即“左”表)上运行aggregate()
方法。 from 参数是目标集合(即“正确”表)。 localField 参数将是源集合中的字段(即“外键”)。 foreignField 参数将是目标集合中的匹配字段。
对于孤立的文档,从您的问题来看,我想您是在考虑传统的RDBMS约束集,级联删除等。从MongoDB 3.2版开始,再次支持文档验证< / em>。看看这篇StackOver的文章:https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/#lookup-aggregation看第二个答案,来自JohnnyHK
Packt发行商在MongoDB上有一堆好书。 (完全公开:我写了几张。)