如何为 Meteor 构建 mongodb
How to structure your mongodb for Meteor
我对 Meteor 很陌生,我正在尝试弄清楚如何实现一些用例。其中之一是投票申请。假设您有几个用户可以对几个民意调查进行投票(为简单起见,我们假设民意调查仅限于 yes/no 个问题)。
每次使用只能投票一次。
在 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
}
]
}
]
如果用户对民意调查投票,则会将一个项目插入民意调查的 votes 数组中。服务器端必须验证用户尚未投票。
为了获得总分,我必须遍历选票,但当然可以通过在包含总分的每个民意调查中创建一个字段来改进,该总分会随着选票的增加而更新。
但是,这如何传播到其他用户?假设将投票添加到民意调查中。整个轮询对象是否被发送到其他连接的客户端?因为如果很多人或投票,投票数组会变大并且会导致很多流量...
但在那种情况下,当管理员用户更改问题(并因此将新版本的轮询对象写入集合)时,更新查询需要知道它只应该更新选定的字段。或者,如果覆盖整个对象,管理员用户应该拥有该对象的最新版本(因为流星是最后写入的)。
我是否遗漏了一些关于此的最佳实践,或者以与建模规范化 SQL 数据库相同的方式对我的集合建模确实更容易?
对数据进行非规范化肯定有利也有弊。因此,总结这两个选项 - 您可以创建一个单独的投票 collection,或者您只是在投票中包含投票 collection。
使用单独的 collection 您肯定会得到一些好处。当使用 #each 模板块遍历游标 (Votes.find({pollId: pollId})) 时,它的性能非常好 - 如果您遍历数组或 collection of objects.
您决定将投票作为 object 包含在民意调查中的一个问题是 DDP 仅在文档的最高级别属性上运行。这意味着每次添加投票时,整个 "votes" object 将被发送到线路。
使用单独的 collection,您还可以获得更好的 publication/subscription 控制的好处。
话虽这么说,如果你只使用一个单独的 collection,你将不得不做一些烦人的事情(如你所提到的)只是为了计算票数,即你必须发布所有投票给客户只是为了计算他们。
许多开发人员选择混合选项,即拥有单独的投票 collection,但也在投票中嵌入一些关于投票的重要属性(例如计数)collection .这也变得有点烦人,这意味着每次有人投票时你都必须更新两个不同的 collection。在这种情况下,我会说你几乎是在正确的轨道上。
Discover Meteor 一书以 Posts 和 Comments 为例,并建议对数据进行非规范化处理,因此(正如您在问题中所建议的那样)在 Poll 上具有单独的 Polls 和 Votes 集合以及 voteCount 属性。
投票时的代码如下所示:
// update the poll with a new vote
Polls.update(vote.pollId, {$inc: {votesCount: 1}});
Votes.insert(vote);
DDP 的运行方式位于文档的顶层,因此这意味着如果选票是 属性 民意调查,每次在民意调查中创建选票时,服务器都会发送整个将投票列表更新到每个连接的客户端。
我对 Meteor 很陌生,我正在尝试弄清楚如何实现一些用例。其中之一是投票申请。假设您有几个用户可以对几个民意调查进行投票(为简单起见,我们假设民意调查仅限于 yes/no 个问题)。 每次使用只能投票一次。
在 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
}
]
}
]
如果用户对民意调查投票,则会将一个项目插入民意调查的 votes 数组中。服务器端必须验证用户尚未投票。 为了获得总分,我必须遍历选票,但当然可以通过在包含总分的每个民意调查中创建一个字段来改进,该总分会随着选票的增加而更新。
但是,这如何传播到其他用户?假设将投票添加到民意调查中。整个轮询对象是否被发送到其他连接的客户端?因为如果很多人或投票,投票数组会变大并且会导致很多流量...
但在那种情况下,当管理员用户更改问题(并因此将新版本的轮询对象写入集合)时,更新查询需要知道它只应该更新选定的字段。或者,如果覆盖整个对象,管理员用户应该拥有该对象的最新版本(因为流星是最后写入的)。
我是否遗漏了一些关于此的最佳实践,或者以与建模规范化 SQL 数据库相同的方式对我的集合建模确实更容易?
对数据进行非规范化肯定有利也有弊。因此,总结这两个选项 - 您可以创建一个单独的投票 collection,或者您只是在投票中包含投票 collection。
使用单独的 collection 您肯定会得到一些好处。当使用 #each 模板块遍历游标 (Votes.find({pollId: pollId})) 时,它的性能非常好 - 如果您遍历数组或 collection of objects.
您决定将投票作为 object 包含在民意调查中的一个问题是 DDP 仅在文档的最高级别属性上运行。这意味着每次添加投票时,整个 "votes" object 将被发送到线路。
使用单独的 collection,您还可以获得更好的 publication/subscription 控制的好处。
话虽这么说,如果你只使用一个单独的 collection,你将不得不做一些烦人的事情(如你所提到的)只是为了计算票数,即你必须发布所有投票给客户只是为了计算他们。
许多开发人员选择混合选项,即拥有单独的投票 collection,但也在投票中嵌入一些关于投票的重要属性(例如计数)collection .这也变得有点烦人,这意味着每次有人投票时你都必须更新两个不同的 collection。在这种情况下,我会说你几乎是在正确的轨道上。
Discover Meteor 一书以 Posts 和 Comments 为例,并建议对数据进行非规范化处理,因此(正如您在问题中所建议的那样)在 Poll 上具有单独的 Polls 和 Votes 集合以及 voteCount 属性。
投票时的代码如下所示:
// update the poll with a new vote
Polls.update(vote.pollId, {$inc: {votesCount: 1}});
Votes.insert(vote);
DDP 的运行方式位于文档的顶层,因此这意味着如果选票是 属性 民意调查,每次在民意调查中创建选票时,服务器都会发送整个将投票列表更新到每个连接的客户端。