MongoDB关系:嵌入还是引用?

MongoDB关系:嵌入还是引用?,mongodb,reference,embed,Mongodb,Reference,Embed,我是MongoDB新手——来自关系数据库背景。我想设计一个带有一些注释的问题结构,但我不知道注释使用哪种关系:embed或reference 一个有一些评论的问题,比如,会有这样的结构: Question title = 'aaa' content = bbb' comments = ??? Question title = 'aaa' content = 'bbb' comments = [ { content = 'xxx', created

我是MongoDB新手——来自关系数据库背景。我想设计一个带有一些注释的问题结构,但我不知道注释使用哪种关系:
embed
reference

一个有一些评论的问题,比如,会有这样的结构:

Question
    title = 'aaa'
    content = bbb'
    comments = ???
Question
    title = 'aaa'
    content = 'bbb'
    comments = [ { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'} ]
db.question.update({'comments.content': 'xxx'}, {'comments.$': true})
首先,我想使用嵌入注释(我认为在MongoDB中建议使用
embed
),如下所示:

Question
    title = 'aaa'
    content = bbb'
    comments = ???
Question
    title = 'aaa'
    content = 'bbb'
    comments = [ { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'} ]
db.question.update({'comments.content': 'xxx'}, {'comments.$': true})
这很清楚,但我担心这种情况:如果我想编辑一条指定的评论,我如何获得它的内容和问题?没有
\u id
让我找到它,也没有
question\u ref
让我找到它的问题。(我是个新手,我不知道如果没有
\u id
问题\u ref
,是否有办法做到这一点)


我是否必须使用
ref
而不是
embed
?然后我必须创建一个新的评论集?

这与其说是一门科学,不如说是一门艺术。这是一个很好的参考,但这里有一些事情需要考虑:

  • 尽可能多地投入

    文档数据库的乐趣在于它消除了大量的连接。您的第一反应应该是尽可能多地在单个文档中放置内容。由于MongoDB文档具有结构,并且您可以在该结构中高效地进行查询(这意味着您可以获取所需的文档部分,因此文档大小不必太担心),因此不需要像SQL中那样立即规范化数据。特别是,任何与其父文档无关的数据都应该是同一文档的一部分

  • 可以从多个位置引用到其自己集合中的独立数据

    这与其说是一个“存储空间”问题,不如说是一个“数据一致性”问题。如果多个记录引用相同的数据,则更新单个记录并在其他位置保留对该记录的引用会更有效,也更不容易出错

  • 文档大小注意事项

    MongoDB对单个文档施加4MB(16MB,1.8)大小限制。在一个GB数据量的世界里,这听起来很小,但它也是30000条推特或250条典型的堆栈溢出答案或20张闪烁的照片。另一方面,这远远超过了一个人在一个典型的网页上一次想要展示的信息。首先考虑什么会使你的查询更容易。在许多情况下,对文档大小的关注将是过早的优化

  • 复杂的数据结构:

    MongoDB可以存储任意深度嵌套的数据结构,但不能有效地搜索它们。如果数据形成树、林或图,则实际上需要将每个节点及其边存储在单独的文档中。(注意,也有专门为这种类型的数据设计的数据存储,也应该考虑)

    此外,它还具有不可能返回文档中元素子集的特性。如果您需要从每个文档中挑选一些内容,那么将它们分开会更容易

  • 数据一致性

    MongoDB在效率和一致性之间进行权衡。规则是对单个文档的更改总是,而对多个文档的更新永远不应该被认为是原子的。也无法在服务器上“锁定”记录(您可以使用例如“锁定”字段将其构建到客户机的逻辑中)。设计模式时,要考虑如何保持数据一致性。通常,文档中保存的内容越多越好

对于您所描述的内容,我将嵌入注释,并为每个注释提供一个带有ObjectID的id字段。ObjectID中嵌入了一个时间戳,因此如果您愿意,可以使用它而不是在创建时使用它

如果我想编辑指定的评论,如何获取其内容和问题

您可以按子文档进行查询:
db.question.find({'comments.content':'xxx'})

这将返回整个问题文档。要编辑指定的注释,您必须在客户端上找到注释,进行编辑并将其保存回数据库


通常,如果您的文档包含一个对象数组,您会发现这些子对象需要在客户端进行修改。

我知道这很旧,但如果您正在寻找OP关于如何仅返回指定注释的问题的答案,您可以使用如下操作符:

Question
    title = 'aaa'
    content = bbb'
    comments = ???
Question
    title = 'aaa'
    content = 'bbb'
    comments = [ { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'} ]
db.question.update({'comments.content': 'xxx'}, {'comments.$': true})

嗯,我有点晚了,但仍然想分享我创建模式的方式

我有所有可以用一个词来描述的模式,就像在经典的OOP中一样

例如

  • 评论
  • 帐目
  • 使用者
  • 博客帖子
每个模式都可以保存为文档或子文档,因此我为每个模式声明了这一点

文件:

  • 可作为参考。(例如,用户发表了评论->评论中有一个对用户的“make by”引用)
  • 是应用程序中的“根”。(例如博客帖子->有一个关于博客帖子的页面)
子文件:

  • 只能使用一次/从不作为参考。(例如,评论保存在blogpost中)
  • 在您的应用程序中永远不是“根”。(评论只显示在blogpost页面上,但该页面仍与blogpost相关)

是的,我们可以使用文档中的引用。要填充另一个文档,就像sql i连接一样。在mongo db中,它们没有连接到映射一对多关系文档。相反,我们可以使用填充来实现我们的场景

var mongoose = require('mongoose')
  , Schema = mongoose.Schema

var personSchema = Schema({
  _id     : Number,
  name    : String,
  age     : Number,
  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
  _creator : { type: Number, ref: 'Person' },
  title    : String,
  fans     : [{ type: Number, ref: 'Person' }]
});
填充是将文档中的指定路径自动替换为其他集合中的文档的过程。我们可以填充单个文档、多个文档、普通对象、多个普通对象或查询返回的所有对象。让我们看一些例子

你最好能得到更多的信息