假设我们有以下文档结构:
class BlogPost
{
[MongoIdentifier]
public Guid Id{get;set;}
public string Body{get;set;}
....
}
class Comment
{
[MongoIdentifier]
public Guid Id{get;set;}
public string Body {get;set;}
}
如果我们假设多个用户可能会发布同一帖子的评论,那么建模这些评论之间关系的最佳方法是什么?
如果Post有一组评论,我可能会遇到并发问题,不是吗?
在Comment上放置一个FK like属性似乎太关系了,或者?
答案 0 :(得分:4)
您基本上有两种选择:1。在帖子文档中汇总评论,或2.模拟帖子和评论作为文档。
如果您聚合评论,您应该a)在帖子上实现修订号,允许您检测竞争条件并实施乐观concurreny的处理,或b)使用MongoDB修饰符添加新评论 - 例如
之类的东西var posts = mongo.GetCollection<Post>();
var crit = new { Id = postId };
var mod = new { Comments = M.Push(new Comment(...)) };
posts.Update(crit, mod, false, false);
如果您将帖子和评论建模为单独的文档,处理并发可能会更容易,但您无法使用单个findOne
命令加载帖子及其评论。
在我看来,(1)是迄今为止最有趣的选项,因为它将帖子建模为聚合对象,这正是你将OO眼镜放在:)上的原因。它绝对是面向文档的方法,而(2)类似于关系数据库的扁平结构。
答案 1 :(得分:2)
这是规范的NoSQL示例之一。执行此操作的标准方法是将Comments
存储为BlogPost
内的对象数组。
为了避免并发问题,MongoDB提供了几个atomic operations。特别是有几个update modifiers适用于“子文档”或“子数组”。
对于“将此评论添加到帖子”,您通常会使用$push
命令将评论附加到帖子。
我看到你正在使用“NoRM”驱动程序。看起来他们支持原子命令,证明by their tests。事实上,他们的测试执行“将此评论推送到博客帖子”。
答案 2 :(得分:0)
他们给出了一个如何对其进行建模的示例over on the MongoDB page on inserting - 我认为您希望在帖子中将一系列评论作为属性公开。你会给一个给定的Post实体添加注释,这会消除将一个Comment实体绑定回它的父Post实体,正如你提出的那样,这个实体在RDBMS中是有意义的,但在NoSQL中却没有那么多溶液
就并发而言,如果你不相信Mongo为你处理这个问题,那么你可能不应该在它上面构建一个应用程序。
答案 3 :(得分:0)
我创建了一个测试应用程序,它产生了1000个并发线程,将“注释”添加到同一个“帖子”中,结果是很多评论都丢失了。
因此,MongoDB将子集合视为单个值,默认情况下不会合并更改。
如果我在帖子上有一个评论集合,那么当两个或更多用户在同一时间添加评论时,我会遇到并发问题(不太可能,但可能)
那么可以在不更新整个帖子对象的情况下向post.comments集合添加评论吗?