首页 文章

MongoDB关系:嵌入还是引用?

提问于
浏览
428

我'm new to MongoDB--coming from a relational database background. I want to design a question structure with some comments, but I don' t知道用于评论的关系: embedreference

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

Question
    title = 'aaa'
    content = bbb'
    comments = ???

首先,我想使用嵌入式注释(我认为在MongoDB中建议使用 embed ),如下所示:

Question
    title = 'aaa'
    content = 'bbb'
    comments = [ { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'} ]

很清楚,但我很担心这种情况: If I want to edit a specified comment, how do I get its content and its question? 没有 _id 让我找到一个,也没有 question_ref 让我找到它的问题 . (我'm so newbie, that I don'知道如果没有 _idquestion_ref ,有没有办法做到这一点 . )

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

10 回答

  • 1

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

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

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

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

  • 661

    通常,如果实体之间存在一对一或一对多的关系,嵌入就很好,如果你有多对多的关系,那么引用就很好 .

  • 9

    实际上,我很好奇为什么没有人谈到UML规范 . 根据经验,如果你有一个聚合,那么你应该使用引用 . 但如果它是一个组合,那么耦合更强,你应该使用嵌入式文档 .

    你会很快理解为什么它是合乎逻辑的 . 如果对象可以独立于父对象存在,那么即使父对象不存在,您也希望访问它 . 由于您无法将其嵌入到不存在的父级中,因此必须将其嵌入到自己的数据结构中 . 如果存在父级,只需通过在父级中添加对象的引用将它们链接在一起 .

    真的不知道这两种关系有什么区别?这是一个解释它们的链接:Aggregation vs Composition in UML

  • 16

    好吧,我有点迟了但仍想分享我的架构创建方式 .

    我有一些可用一个词描述的模式,就像你在古典OOP中所做的那样 .

    例如 .

    • 评论

    • 帐户

    • 用户

    • Blogpost

    • ......

    每个模式都可以保存为Document或Subdocument,因此我为每个模式声明了这一点 .

    文献:

    • 可以作为参考 . (例如,用户发表评论 - >评论有"made by"对用户的引用)

    • 在您的应用程序中是"Root" . (例如,博文 - >有关于博客帖子的页面)

    子文档:

    • 只能使用一次/永远不能作为参考 . (例如,评论保存在博文中)

    • 在您的应用程序中永远不是"Root" . (评论只显示在博客帖子页面,但页面仍然是关于博客帖子)

  • 32

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

    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' }]
    });
    

    填充是使用来自其他集合的文档自动替换文档中的指定路径的过程 . 我们可以填充单个文档,多个文档,普通对象,多个普通对象或从查询返回的所有对象 . 我们来看一些例子 .

    更好的是你可以获得更多信息,请访问:http://mongoosejs.com/docs/populate.html

  • -1

    我知道这已经很老了但是如果你正在寻找关于如何只返回指定注释的OP问题的答案,你可以像这样使用$ (query)运算符:

    db.question.update({'comments.content': 'xxx'}, {'comments.$': true})
    
  • 24

    这更像是一门艺术,而不是一门科学 . Mongo Documentation on Schemas是一个很好的参考,但这里有一些事情需要考虑:

    • 尽可能多地投入

    Document数据库的乐趣在于它消除了大量的连接 . 你的第一直觉应该是尽可能多地放在一个文件中 . 因为MongoDB文档具有结构,并且因为您可以在该结构中有效地进行查询(这意味着您可以获取所需文档的一部分,因此文档大小不应该太担心)没有立即需要对数据进行规范化你会在SQL中 . 特别是除了其父文档之外没有用的任何数据应该是同一文档的一部分 .

    • 将可以从多个位置引用的数据分隔到其自己的集合中 .

    这不是一个“存储空间”问题,因为它是一个“数据一致性”问题 . 如果许多记录将引用相同的数据,则更高效且更不容易更新单个记录并在其他位置保留对它的引用 .

    • 文档大小注意事项

    MongoDB对单个文档施加了4MB(16MB,1.8)大小限制 . 在GB数据的世界中,这听起来很小,但它也是3万条推文或250个典型的Stack Overflow答案或20张闪烁的照片 . 另一方面,这是更多在一个典型的网页上,一次可能想要呈现的信息 . 首先考虑什么会使您的查询更容易 . 在许多情况下,对文档大小的关注将是过早优化 .

    • 复杂的数据结构:

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

    它还具有been pointed out,而不可能返回文档中的元素子集 . 如果您需要挑选每个文档的几个部分,将它们分开将更容易 .

    • 数据一致性

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

    对于您所描述的内容,我会嵌入注释,并为每个注释指定一个带有ObjectID的id字段 . ObjectID中嵌入了一个时间戳,因此您可以使用它而不是根据需要创建 .

  • 0

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

    如果您已跟踪注释的数量和要更改的注释的索引,则可以使用the dot operatorSO example) .

    你可以做f.ex.

    db.questions.update(
        {
            "title": "aaa"       
        }, 
        { 
            "comments.0.contents": "new text"
        }
    )
    

    (作为编辑问题内部评论的另一种方式)

  • 15

    我在自己研究这个问题时遇到了这个小小的演讲 . 我对它的布局表现感到惊讶,包括它的信息和表现 .

    http://openmymind.net/Multiple-Collections-Versus-Embedded-Documents

    它总结如下:

    作为一般规则,如果您有很多[子文档]或者它们很大,那么单独的集合可能是最好的 . 较小和/或较少的文档往往适合嵌入 .

  • 17

    这取决于文档的用法 . 当您使用该文档时,如果您始终使用注释,则使用嵌入的最佳方法 . 但您应该考虑最大文档大小(16MB) .

相关问题