0

假设我有一个文档和一个作者集合。我可以通过两种方式设计它:

第一种方式:

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}

第一种方法很好,因为我在检索文档时不必模拟 Join,我拥有文档集合中的所有数据。但是,另一方面,如果我必须改变 Maria 的年龄,我必须在两个系列中都这样做。

第二种方式相反,如果我需要一个文档及其作者的年龄,我需要先查询文档,然后再查询作者。但好消息是,当我必须更改 Maria 的年龄时,我只需要在作者集合中进行。

那么,哪种解决方案更好?我想您在作者集合中需要的字段越多,您使用第二种方式的可能性就越大。但是,如果我使用第一种方式,是否可以使用一个查询来更新两个集合中 Maria 的年龄?

哪个是最常用的解决方案?

4

3 回答 3

2

多个集合中的更新将是一个事务。MongoDB 不支持事务。

两种方式都有各自的缺点。

第一种包含作者数据的方式可能更适合于其内容不会发生变化的日志记录情况。

当您期望作者的详细信息会随着时间而改变或增长时(大多数情况下),第二种方法会更好。

就像已经提到的那样,将文档嵌入到各自作者的文档中将是结合这两个建议的好处的一种方式,但从长远来看可能会导致问题。

于 2013-02-07T10:12:57.090 回答
1

第一种方法的问题是更新:

{_id:1, title:"document 1", author:"John", age: 34}

我可以想象,实际上你会想要一个作者 ID 以及查询所需的一些细节(模式冗余)。

正如您所注意到的,这可能会带来问题:

但是,另一方面,如果我必须改变 Maria 的年龄,我必须在两个系列中都这样做。

年龄至少每年变化一次,如果年龄错误,则更频繁。姓名也可以更改,尤其是当您后来发现这个“约翰”有姓氏或者他的名字实际上是“约翰尼”时。

因此,在这里创建冗余的问题是作者文档可能会发生巨大变化,导致您必须运行性能极差的更新,这有时会大大增加您的工作集。至于它多久会导致这种情况,我不能用提供的信息说,这将由你决定。

通常,创建冗余的一种好方法是当您在当前文档的另一个文档中需要极少更新的属性时。这似乎不是这里的情况。

第二种方法通常是进行这种随机读取和更新关系的默认方法,但是还有第三种方法 - 嵌入。

您可以将文档嵌入到作者中。这取决于您要存储多少文档,因为 MongoDB 的最大文档大小为 16Meg。

话虽如此,一种可能性是:

{
    _id: {},
    name: 'John',
    age: 43,
    documents: [
        { id: 1, title: "New Document" }
    ]
}

这样做的一个缺点是使用内存中的操作,例如$pullor$push不仅如此,而且如果您的文档持续且大幅增长,您可能会看到碎片。

但同样,这些只是供您参考的笔记,实际上取决于未提供的信息。

于 2013-02-07T10:07:13.013 回答
1

我建议混合使用这两种方法,“静态”信息将与文档集合一起保存,变量数据将集中在作者集合中,只有当需要检索变量数据时,我才会使用作者 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 不是事务性的,如果您一次性创建作者和文档,您可能会遇到问题。

于 2013-02-07T17:09:36.820 回答