我正在建立论坛,提出像SO这样的问题和答案。我的数据库是MongoDB,我的问题是如何正确存储和计算与post相关的计数器?
例如,我有两个集合:
文章:
[{
_id: ObjectId(1),
title: 'Untitled',
content: 'empty'
}]
投票:
[{
_post: ObjectId(1),
_user: ObjectId(...),
vote: 1,
}, {
_post: ObjectId(1),
_user: ObjectId(...),
vote: 1,
}]
当用户投票使用ObjectId(1)
发帖时,他会发出以下查询:
Votes.create({_post: ObjectId(1), vote: 1}).exec(cb);
所有看起来都很好但是当我需要获取最后100个帖子的大块时,我会遇到性能问题。我需要的是:
我想修复性能问题,并在Post schema附加字段中计算投票次数:
[{
_id: ObjectId(1),
title: 'Untitled',
content: 'empty',
votes: 2
}]
但在这种情况下,我注意以某种方式支持一致性和原子更新在Votes集合中创建新投票时投票。
您能否建议最佳做法来支持帖子和投票集合之间的一致性?
谢谢!
我知道我可以在帖子中使用嵌入和存储投票数组,但我不想要,因为我的帖子可能会增长,我可能会遇到其他性能问题
答案 0 :(得分:2)
正如许多人所说的那样,当模型间关系变得重要时,NoSQL并不是最好的工作;那就是说,让我们尝试列出你的两个重要业务目标:
当然,你是在正确的轨道上缓存计数 - 但如果准确性对你很重要,那么我会做两件事:
votes
字段,而是使用适当索引的Votes
集合上的查询填充createdAt
和updatedAt
样式时间戳来确保缓存的结果仅在上一个时间之后被计算值替换:)是的,它不是原子的,但是它确实有助于确保只缓存最相关的值(以毫秒精度衡量)现在,如果你想要全力以赴,那么适当的做法就是拥有一个与cron不同的单一服务,每隔几分钟就会针对那些具有较新updatedAt
s的服务。然而,聪明地完成(2)应该使这不必要。
希望这有帮助!
示例强>
Posts
_id:“f00b4r”,数据:{...},投票:0,createdAt:“2016-05-23T07:27:33.043Z”,更新时间:“2016-05-23T07:27:33.043Z”
现在,用户点击向下投票,所以发生了以下情况:
Votes
_id:“sn4fuu”,user_id:“j0hnd03”post_id:“f00b4r”,值:-1,createdAt:“2016-05-23T07:28:33.043Z”,更新时间:“2016-05-23T07:28 :33.043Z“
我们的代码(比如说NodeJS)现在也会触发Votes
post_id: f00b4r
的所有-1
(一个索引字段,速度!)的查询,它的值为Posts
。< / p>
我们以编程方式保存,以便updatedAt
现在看起来像这样:
_id:“f00b4r”,数据:{...},票数:-1,createdAt:“2016-05-23T07:27:33.043Z”,更新时间:“2016-05-23T07:28:33.043Z “
请注意updatedAt
从07:27到07:28已经消失了!
我们使用Posts
集合中的最新updatedAt
填充Votes
上的updatedAt
,以确保最终缓存的投票中只有最新的更新结果 - 伯爵(是的,你认为你在这里也需要一个索引是正确的)!如果我们的代码找到比它要保存的更新的Votes
,它会意识到它已经过时的信息并且不会脏写它!
现在,如果用户将向下投票更改为向上投票:
Posts
_id:“sn4fuu”,user_id:“j0hnd03”post_id:“f00b4r”,值:1,createdAt:“2016-05-23T07:28:33.043Z”,更新时间:“2016-05-23T07:29: 33.043Z“
Votes
_id:“f00b4r”,数据:{...},投票:1,createdAt:“2016-05-23T07:27:33.043Z”,更新时间:“2016-05-23T07:29:33.043Z”
由于我们每次都在查询myView.accessibilityIdentifier = @"YOYO";
,因此我们也可以获得复杂场景的合法值,因为我们不会直接递增或递减缓存。
答案 1 :(得分:-2)
投票:
[{
_post: ObjectId(1),
_user: [ObjectId(...),ObjectId(...),ObjectId(...),ObjectId(...)],
}, {
_post: ObjectId(2),
_user: [ObjectId(...),ObjectId(...),ObjectId(...),ObjectId(...)],
}]