假设我有一个文档和一个作者集合。我可以用两种方式设计它:
第一种方式:documents
{_id:1, title:"document 1", author:"John", age: 34}
{_id:2, title: "document 2", author: "Maria", age:42 }
{_id:3, title: "document 3", author: "John", age: 34}
authors
{_id:1, name:"John", age:34}
{_id:2, name:"Maria", age:42}
第二种方式:
documents
{_id:1, title:"document 1", id_author:1}
{_id:2, title: "document 2", id_author: 2}
{_id:3, title: "document 3", id_author: 1}
authors
{_id:1, name:"John", age:34}
{_id:2, name:"Maria", age:42}
第一种方式很好,因为我在检索文档时不必模拟连接,我拥有文档集合中的所有数据。但是,另一方面,如果我必须改变玛丽亚的年龄,我必须在两个系列中都这样做。
第二种方式恰恰相反,如果我需要一个文件及其作者的年龄,我需要先查询文档,然后再查询作者。但好处是,当我必须改变玛丽亚的年龄时,我只需要在作者集合中进行。
那么,哪种解决方案更好?我想你在作者集合中需要的字段越多,你就越有可能使用第二种方式。但是,如果我使用第一种方式,是否有一个查询我可以用来更新两个集合中Maria的年龄?
哪种解决方案最常用?
答案 0 :(得分:2)
多个集合中的更新将是一个事务。 MongoDB不支持事务。
两种方式都有其自身的缺点。
第一种包含作者数据的方式可能更适合于记录其内容不会发生变化的情况。
当你期望作者的细节随着时间的推移而变化或增长时(第二种情况),第二种方式会更好。
就像已经提到的那样,将文档嵌入各自作者的文档中将是一种结合2个建议的好处的方法,但从长远来看可能会导致问题。
答案 1 :(得分:1)
第一种方法的问题是更新:
{_id:1, title:"document 1", author:"John", age: 34}
我可以想象,实际上你需要一个作者ID以及查询所需的一些细节(模式冗余)。
正如您所注意到的那样,这可能会造成问题:
但是,另一方面,如果我必须改变玛丽亚的年龄,我必须在两个系列中都这样做。
年龄变化至少每年一次,如果你的年龄错了,更经常。名字也可以改变,特别是如果你以后发现这个“John”有一个姓氏或者他的名字实际上是“Johnny”。
因此,在此处创建冗余的问题在于,作者文档可能会发生巨大变化,导致您必须运行极其无理性的更新,这可能会大量增加您的工作集。至于它引起这种情况的频率,我不能用所提供的信息说出来,那将由你决定。
通常,创建冗余的好方法是在当前文档中的另一个文档中需要极少更新的属性。这似乎不是这种情况。
第二种方式通常是进行这种随机读取和更新关系的默认方式,但是有一种可能的第三种方法 - 嵌入。
您可以将文档嵌入到作者中。这取决于您希望存储的文档数量,因为MongoDB的最大文档大小为16Meg。
据说有可能是:
{
_id: {},
name: 'John',
age: 43,
documents: [
{ id: 1, title: "New Document" }
]
}
这样做的另一个方面是使用内存操作,例如$pull
或$push
,不仅如此,但如果您的文档一直在大幅增长,您可能会看到碎片。
但这些只是你要注意的内容,实际上取决于未提供的信息。
答案 2 :(得分:1)
我建议混合使用这两种方法,“静态”信息将与文档集合一起保存,变量数据将集中在authors集合中,只有当需要检索变量数据时才会使用作者ID来检索他的年龄。像这样:
documents
{_id:"1", title:"document 1", author:"John", authorId: "1"}
{_id:"2", title: "document 2", author: "Maria", authorId: "2"}
{_id:"3", title: "document 3", author: "John", authorId: "1"}
authors
{_id:"1", name:"John", age:34}
{_id:"2", name:"Maria", age:42}
年龄是你经常不需要的东西,但可以经常更新,因此这将更好地处理这两种情况。
正如其他人提到的那样,Mongo不是交易性的,如果你一次性创建作者和文档,你可能会遇到问题。