如何使用MongoDB为"喜欢"的投票系统建模

use*_*635 12 data-modeling mongodb mongodb-query

目前我正在开发一款移动应用.基本上人们可以发布他们的照片,而粉丝可以喜欢像Instagram这样的照片.我使用mongodb作为数据库.像Instagram一样,单张照片可能会有很多喜欢.因此,使用带有索引的单个"喜欢"的文档似乎不合理,因为它会浪费大量内存.但是,我希望用户快速添加.所以我的问题是如何建模"喜欢"?基本上,数据模型与instagram非常相似,但使用的是Mongodb.

Nei*_*unn 36

无论您如何构建整个文档,基本上都需要两件事.这基本上是已经发布"喜欢"的人的"计数"和"列表"的属性,以确保没有提交重复项.这是一个基本结构:

{ 
    "_id": ObjectId("54bb201aa3a0f26f885be2a3")
    "photo": "imagename.png",
    "likeCount": 0
    "likes": []
}
Run Code Online (Sandbox Code Playgroud)

无论如何,对于您的"照片帖子"以及您想要的任何信息,都有一个独特的"_id",然后是所提到的其他字段.这里的"likes"属性是一个数组,它将保存系统中"user"对象的唯一"_id"值.因此,每个"用户"在某处都有自己的唯一标识符,无论是在本地存储中还是在OpenId中,都是唯一的标识符.我会坚持ObjectId这个例子.

当有人向帖子提交"赞"时,您希望发出以下更新语句:

db.photos.update(
    { 
        "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
        "likes": { "$ne": ObjectId("54bb2244a3a0f26f885be2a4") }
    },
    {
        "$inc": { "likeCount": 1 },
        "$push": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
    }
)
Run Code Online (Sandbox Code Playgroud)

现在,$inc那里的操作会将"likeCount"的值增加指定的数量,因此增加1. $push操作将用户的唯一标识符添加到文档中的数组中以供将来参考.

这里最重要的是记录那些投票的用户以及在声明的"查询"部分发生的事情.除了通过它自己独特的"_id"选择要更新的文档之外,另一个重要的事情是检查"喜欢"数组以确保当前的投票用户不在那里.

相反情况或"删除""喜欢"也是如此:

db.photos.update(
    { 
        "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
        "likes": ObjectId("54bb2244a3a0f26f885be2a4")
    },
    {
        "$inc": { "likeCount": -1 },
        "$pull": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
    }
)
Run Code Online (Sandbox Code Playgroud)

这里最重要的是查询条件,用于确保在未满足所有条件时不触及任何文档.因此,如果用户已经投票或减少,如果他们的投票在更新时实际上不再存在,则计数不会增加.

当然,在应用程序的任何其他部分中读取文档中包含几百个条目的数组是不切实际的.但MongoDB也有一种非常标准的方法来处理它:

db.photos.find(
    { 
        "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
    },
    { 
       "photo": 1
       "likeCount": 1,
       "likes": { 
          "$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") }
       }
    }
)
Run Code Online (Sandbox Code Playgroud)

$elemMatch投影中的这种用法只会返回当前用户(如果存在)或仅返回空白数组.如果当前用户已经投票,则允许其余的应用程序逻辑知道.

这是基本技术,可能对您有用,但您应该知道嵌入式阵列不应无限扩展,并且BSON文档也有16MB的硬限制.所以这个概念是合理的,但是如果你期望在你的内容上有1000个"赞票",就不能单独使用它.存在称为"分段"的概念,在该示例中针对混合模式设计进行了一些详细讨论,其允许一种解决方案存储大量"喜欢".您可以将其与基本概念一起使用,作为在卷上执行此操作的方法.

  • 很好的答案,很抱歉提出这个问题,但是你对实现这样的解决方案有什么想法(而不是使用子文档来保持喜欢或投票)http://stackoverflow.com/questions/26914380/schema-for-user-ratings -key值-DB (2认同)
  • @ user2914635你现在要问的是另一个问题,但即使如此,它也是一个非常广泛的问题.如果你想浏览不同的技巧并且不介意阅读一些代码,那么你可以看看[hvdf](https://github.com/10gen-labs/hvdf)和[socialite](https: //github.com/10gen-labs/hvdf)来源.达伦甚至有一些像[这一个]的谈话(http://www.mongodb.com/presentations/socialite-open-source-status-feed-part-3-scaling-data-feed).同时考虑将300,000个喜欢的地方作为例外,而不是规则. (2认同)
  • @Neil Lunn.基本上,分组设计的专业是它节省内存并且易于检索喜欢向最终用户显示,分组设计的缺点是它使插入更加昂贵.将每个像单个文档一样处理的专家是它使得插入效率高,并且检索喜欢也具有合理的性能,但是它会浪费大量的内存.我是否正确?据我所知,Instagram通常会有很多喜欢的帖子.假设我也有很多喜欢的帖子.我应该采用哪种数据模型?需要您的建议,提前感谢 (2认同)