我想设计一个带有一些评论的问题结构。注释应该使用哪种关系:嵌入还是引用?

一个带有注释的问题,比如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'} ]

这很清楚,但我担心这种情况:如果我想编辑一个指定的评论,我如何获得它的内容和它的问题?没有_id让我找到一个,也没有question_ref让我找到它的问题。(也许有一种方法可以做到这一点没有_id和question_ref?)

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


当前回答

好吧,我有点晚了,但仍然想分享我的模式创建方法。

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

E.G.

评论 账户 用户 博客 ...

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

文档:

可以作为参考。(例如,用户做了一个评论->评论有一个“由”的参考用户) 是应用程序中的“根”。(例如,博客文章->有一个关于博客文章的页面)

子文档:

只能使用一次/绝不是参考。(例如,评论保存在博客文章中) 在应用程序中从来都不是“根”。(评论只在博客页面中显示,但页面仍然是关于博客的)

其他回答

我知道这是相当古老的,但如果你正在寻找OP关于如何只返回指定注释的问题的答案,你可以像这样使用$(查询)操作符:

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

如果我想编辑一个指定的评论,如何获得它的内容和它的问题?

您可以通过子文档进行查询:Content ': 'xxx'})。

这将返回整个Question文档。要编辑指定的评论,您必须在客户端上找到该评论,进行编辑并将其保存回DB。

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

MongoDB提供了无模式的自由,如果没有考虑或计划好,这个特性可能会导致长期的痛苦,

有2个选项,嵌入或引用。我不会详细解释定义,因为上面的答案已经很好地定义了它们。

当嵌入时,你应该回答一个问题,你嵌入的文档是否会增长,如果是,那么有多少(记住每个文档有16mb的限制)所以,如果你有一个帖子的评论,什么是评论计数的限制,如果这个帖子病毒式传播,人们开始添加评论。在这种情况下,引用可能是更好的选择(但甚至引用也会增长,达到16mb的限制)。

因此,如何平衡它,答案是不同模式的组合,检查这些链接,并根据您的用例创建自己的混合和匹配。

https://www.mongodb.com/blog/post/building-with-patterns-a-summary

https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-1

一般来说,如果实体之间有一对一或一对多的关系,则嵌入是很好的选择;如果实体之间有多对多的关系,则引用是很好的选择。

是的,我们可以使用文件中的参考资料。就像SQL i连接一样填充另一个文档。在MongoDB中,它们没有连接来将一个关系文档映射到多个关系文档。相反,我们可以使用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