我对Meteor很陌生,我正试图弄清楚如何实现一些用例。其中一个是投票申请。假设您有几个用户可以对几个民意调查进行投票(为简单起见,我们假设民意调查仅限于是/否问题)。 每次使用只能投票一次。
在SQL中,我会在3个表中对此进行规范化:
USER (id/name)
VOTES (user_id/poll_id/choice)
POLLS (id/question)
然而,在mongodb的文档存储世界中,似乎鼓励将投票存储在一个包含民意调查的集合中,如下所示:
[
{
_id: 1234
question: "the question"
votes:
[
{
user_id: 1
choice: 1
}
]
}
]
如果用户对投票进行投票,则项目将插入投票的投票数组中。服务器端必须验证用户尚未投票。 要获得总得分,我必须迭代投票,但当然可以通过在每个包含聚合得分的投票上创建一个字段来改进,该得分随着投票的增加而更新。
但是,这如何传播给其他用户?假设投票被添加到投票中。整个民意调查对象是否会被发送到其他连接的客户端?因为如果很多人投票,投票数组会变大,会造成大量的流量......
但是在这种情况下,当管理员用户更改问题(并因此将新版本的轮询对象写入集合)时,更新查询需要知道它只应更新所选字段。或者,如果覆盖整个对象,管理员用户应该拥有最新版本的对象(因为meteor是last-write-wins)。
我是否遗漏了一些关于此的最佳实践,或者对我的集合建模确实更容易,就像我为规范化的SQL DB建模一样?
答案 0 :(得分:1)
对数据进行非规范化肯定有利有弊。因此,总结这两个选项 - 您要么创建一个单独的投票集合,要么只是在您的民意调查集合中包含投票。
通过单独的收藏,您肯定会获得一些好处。当使用#each模板块迭代游标(Votes.find({pollId:pollId}))时,它非常高效 - 如果你正在迭代一个数组或一组对象,那就更好了。
您决定将投票作为投票包含在投票中的一个问题是DDP仅在文档的最高级别属性中运行。这意味着每次增加投票时,整个"投票"对象将被发送出去。
通过单独的集合,您还可以获得更好的发布/订阅控制权。
话虽如此,如果你只使用一个单独的集合,你将不得不做一些烦人的事情(如你所提到的)只是为了获得投票数,即你必须将所有投票发布给客户只是为了算上他们。
许多开发人员选择混合选项,即具有单独的Votes集合,但也在Polls集合中嵌入一些关于投票(例如计数)的重要属性。这也变得有点烦人,这意味着每次有人投票时你都必须更新两个不同的集合。在这种情况下,我说你几乎走在正确的轨道上。
答案 1 :(得分:1)
Discover Meteor书籍使用帖子和评论作为示例,并建议对数据进行非规范化,因此(正如您在问题中所建议的那样)在民意调查中具有单独的民意调查和投票集合以及voteCount属性。
投票时的代码如下所示:
// update the poll with a new vote
Polls.update(vote.pollId, {$inc: {votesCount: 1}});
Votes.insert(vote);
DDP的运作方式是在文档的顶层,这意味着如果投票是投票的属性,每次在投票上创建投票时,服务器都会发送该投票的整个更新投票列表每个连接的客户端。