如何模拟“喜欢"MongoDB 投票系统 [英] How to Model a "likes" voting system with MongoDB

查看:35
本文介绍了如何模拟“喜欢"MongoDB 投票系统的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

解决方案

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

{"_id": ObjectId("54bb201aa3a0f26f885be2a3")"照片": "图像名称.png",喜欢计数":0喜欢":[]}

无论如何,您的照片帖子"和您想要的任何信息都有一个唯一的_id",但其他字段也如上所述.这里的likes"属性是一个数组,它将保存来自系统中user"对象的唯一_id"值.所以每个用户"在某处都有自己的唯一标识符,无论是在本地存储还是 OpenId 或其他东西,但一个唯一的标识符.我将坚持使用 ObjectId 作为示例.

当有人向帖子提交赞"时,您希望发布以下更新声明:

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

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

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

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

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

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

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

db.photos.find({"_id": ObjectId("54bb201aa3a0f26f885be2a3"),},{照片":1"likeCount": 1,喜欢":{"$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") }}})

$elemMatch的这种用法 在投影中只会在当前用户存在时返回当前用户,或者在不存在时返回一个空白数组.这允许应用程序的其余部分知道当前用户是否已经投票.

这是基本技术,可能对您有用,但您应该意识到嵌入式数组不应无限扩展,并且 BSON 文档也有 16MB 的硬限制.所以这个概念是合理的,但如果您期望在您的内容上获得 1000 个喜欢投票",就不能单独使用它.有一个称为bucketing"的概念,在此示例中详细讨论了 混合架构设计,允许一种解决方案来存储大量喜欢".您可以将其与此处的基本概念一起使用,以此作为批量执行此操作的一种方式.

Currently I am working on a mobile app. Basically people can post their photos and the followers can like the photos like Instagram. I use mongodb as the database. Like instagram, there might be a lot of likes for a single photos. So using a document for a single "like" with index seems not reasonable because it will waste a lot of memory. However, I'd like a user add a like quickly. So my question is how to model the "like"? Basically the data model is much similar to instagram but using Mongodb.

解决方案

No matter how you structure your overall document there are basically two things you need. That is basically a property for a "count" and a "list" of those who have already posted their "like" in order to ensure there are no duplicates submitted. Here's a basic structure:

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

Whatever the case, there is a unique "_id" for your "photo post" and whatever information you want, but then the other fields as mentioned. The "likes" property here is an array, and that is going to hold the unique "_id" values from the "user" objects in your system. So every "user" has their own unique identifier somewhere, either in local storage or OpenId or something, but a unique identifier. I'll stick with ObjectId for the example.

When someone submits a "like" to a post, you want to issue the following update statement:

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

Now the $inc operation there will increase the value of "likeCount" by the number specified, so increase by 1. The $push operation adds the unique identifier for the user to the array in the document for future reference.

The main important thing here is to keep a record of those users who voted and what is happening in the "query" part of the statement. Apart from selecting the document to update by it's own unique "_id", the other important thing is to check that "likes" array to make sure the current voting user is not in there already.

The same is true for the reverse case or "removing" the "like":

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

The main important thing here is the query conditions being used to make sure that no document is touched if all conditions are not met. So the count does not increase if the user had already voted or decrease if their vote was not actually present anymore at the time of the update.

Of course it is not practical to read an array with a couple of hundred entries in a document back in any other part of your application. But MongoDB has a very standard way to handle that as well:

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

This usage of $elemMatch in projection will only return the current user if they are present or just a blank array where they are not. This allows the rest of your application logic to be aware if the current user has already placed a vote or not.

That is the basic technique and may work for you as is, but you should be aware that embedded arrays should not be infinitely extended, and there is also a hard 16MB limit on BSON documents. So the concept is sound, but just cannot be used on it's own if you are expecting 1000's of "like votes" on your content. There is a concept known as "bucketing" which is discussed in some detail in this example for Hybrid Schema design that allows one solution to storing a high volume of "likes". You can look at that to use along with the basic concepts here as a way to do this at volume.

这篇关于如何模拟“喜欢"MongoDB 投票系统的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆