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

时间:2015-01-18 02:19:36

标签: mongodb mongodb-query data-modeling

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

1 个答案:

答案 0 :(得分:33)

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

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

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

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

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

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

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

对于相反情况或“删除”“喜欢”也是如此:

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

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

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

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

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

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