MongoDB架构设计 - 在帖子上投票

时间:2012-07-03 13:50:53

标签: mongodb

考虑一下我有一个网站,我有一堆文章,人们可以投票他们喜欢的文章。

我希望能够在一定时间内(最后一小时,最后一天,上周)以投票数排序获得投票最多的文章。

与MongoDB一样,有几种不同的方法可以实现这一点,但我不确定哪一种是正确的。

  • 一个帖子文档,其中包含一个投票数组 - 投票本身就是包含用户ID,用户名和投票日期的文件:
    {
    "_id": "ObjectId(xxxx)",
    "title": "Post Title",
    "postdate": "21/02/2012+1345",
    "summary": "Summary of Article",

    "Votes": [
        {
            "userid":ObjectId(xxxx),
            "username": "Joe Smith",
            "votedate": "03/03/2012+1436"
        },
            ]
     }
  • 单独的投票收集,包含个人投票的详细信息和对投票的帖子的引用:
{
    "_id": "ObjectId(xxxx)",
    "postId": ObjectId(xxxx),
    "userId": ObjectId(xxxx),
    "votedate": "03/03/2012+1436"
}

第一个更像是Documentey,但我不知道如何查询投票数组以获得过去24小时内投票最多的文件。

我倾向于第二个,因为我更容易查询按照投票分组的投票计数,但我不确定它的效果如何。这就是你在关系数据库中做到这一点的方法,但它看起来并不是很有文档 - 但我不确定它是否有问题,是吗?

或者我使用两者的组合?我也会实时,每页加载这种类型的聚合查询。或者我只是每分钟运行一次查询,并将结果存储在查询结果集合中?

您将如何实施此架构?

2 个答案:

答案 0 :(得分:10)

跟踪总体投票数的常用方法是保留帖子文档中的投票数,并在将新值推送到投票数组时以原子方式更新投票数。

由于这是一次更新,因此可以保证计数与数组中的元素数量相匹配。

如果聚合数量固定且网站非常繁忙,您可以扩展此范例并增加额外的计数器,例如月,日和小时的计数器,但这可能会很快失控。因此,你可以使用新的Aggregation Framework(在2.1.2开发版中提供,将在2.2版本中生产。它比Map / Reduce更简单,它可以让你进行你想要的计算特别是如果你注意把你的投票日期存储为ISODate()类型。

本月顶级投票获取者聚合查询的典型管道可能如下所示:

today = new Date();
thisMonth = new Date(today.getFullYear(),today.getMonth());
thisMonthEnd = new Date(today.getFullYear(),today.getMonth()+1);

db.posts.aggregate( [
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } },
    {$unwind: "$Votes" },
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } },
    {$group: { _id: "$title", votes: {$sum:1} } },
    {$sort: {"votes": -1} },
    {$limit: 10}
] );

这会将输入限制为通过将投票日期与您计算的月份匹配而具有投票权的帖子的输入,“展开”数组以获得每个投票一个文档,然后执行“group by”等效总结所有投票每个标题(我假设标题是唯一的)。然后按投票数下降,并将输出限制在前十位。

您还可以按月累计投票(例如),查看投票最活跃的日期:

db.posts.aggregate( [
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } },
    {$unwind: "$Votes" },
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } },
    {$project: { "day" : { "$dayOfMonth" : "$Votes.votedate" }  } },
    {$group: { _id: "$day", votes: {$sum:1} } },
    {$sort: {"votes": -1} },
    {$limit: 10}
] );

答案 1 :(得分:0)

您选择的架构在很大程度上取决于您的使用情况。如果您期望获得大量投票/评论并希望独立于其所属的帖子处理它们,您可以将它们保存在一个单独的集合中,其中postID为'foriegn key'..但是,如果你想在加载一个特定的帖子时加载所有的投票而且投票本身没有任何意义而没有包含它们的帖子,那么去嵌入(在你的情况下) ,第一种方法。