Article {
"_id" : "A",
"title" : "Hello World",
"user_id" : 12345,
"text" : 'My test article',
"comments" : [
{ 'text' : 'blah', 'user_id' : 654321, 'votes' : [987654]},
{ 'text' : 'foo', 'user_id' : 987654, 'votes' : [12345, 654321] },
...
]
}
这里的基本前提是我将Comments 嵌套在Article 中。 Votes 仅适用于 Comment,因此它们已存储为每个 Comment 的数组。在这种情况下,我刚刚存储了 user_id。如果要存储更多信息(time_created 等),则可以对对象数组进行投票:
... 'votes' : [ { user_id : 987654, ts : 78946513 } ] ...
如何高效地执行查询:
- 获取文章 A、文章 A 的 cmets 以及每个 cmets 的投票数
db.articles.find( { _id : 'A' } )
这可以通过一个查询获得所有内容。您可能需要执行一些客户端逻辑来计算每条评论的投票数,但这非常简单。
- 获取用户 B 在所有文章中的所有 cmets
db.articles.ensureIndex( { "comments.user_id" : 1 } )
db.articles.find( { "comments.user_id" : 987654 } ) // returns all document fields
索引将允许有效地搜索文档中的 cmets。
目前无法仅从子数组中提取匹配项。该查询实际上将返回该用户的所有带有 cmets 的文章。如果这可能是数据过多,您可以进行一些修剪。
db.articles.find( { "comments.user_id" : 987654 }, { "title" : 1, "comments.user_id" : 1 })
- 获取用户 B 投票支持的所有 cmets
db.articles.ensureIndex( { "comments.votes" : 1 } )
db.articles.find( { "comments.votes" : 987654 } )
同样,这将返回所有文章,而不仅仅是 cmets。
这里需要权衡取舍。退回文章可能看起来我们带回了太多数据。但是,当您进行查询 #3 时,您打算向用户显示什么?
如果没有评论本身,获取“我投票支持的cmets”的列表并不是非常有用。当然,如果没有文章本身(或至少只是标题),评论就不是很有用。
大多数情况下,查询 #3 会演变为从 Votes 到 Comments 到 Articles 的连接。如果是这样,那为什么不把文章带回来呢?