目前我正在开发一款移动应用程序.基本上,人们可以发布自己的照片,粉丝们也可以喜欢Instagram这样的照片.我使用mongodb作为数据库.像instagram一样,一张照片可能会有很多人喜欢.因此,将文档用于带有索引的单个"like"似乎不合理,因为这将浪费大量内存.但是,我希望用户快速添加一个like.所以我的问题是如何模拟"like"?基本上,数据模型与instagram非常相似,但使用的是Mongodb.
目前我正在开发一款移动应用程序.基本上,人们可以发布自己的照片,粉丝们也可以喜欢Instagram这样的照片.我使用mongodb作为数据库.像instagram一样,一张照片可能会有很多人喜欢.因此,将文档用于带有索引的单个"like"似乎不合理,因为这将浪费大量内存.但是,我希望用户快速添加一个like.所以我的问题是如何模拟"like"?基本上,数据模型与instagram非常相似,但使用的是Mongodb.
无论你如何构建你的整体文档,基本上你需要两件事.这基本上是一个"计数"和"名单"的财产,这些人已经发布了他们的"喜欢",以确保没有重复提交.以下是一个基本 struct :
{
"_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" Select 要更新的文档外,另一件重要的事情是判断"likes"数组,以确保当前投票用户不在其中.
反之亦然,或"删除"了"like":
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的硬限制.因此,这个概念是合理的,但如果你希望在你的内容上获得Hybrid Schema design0张"赞成票",就不能单独使用.有一个称为"bucketing"的概念,在本例中对其进行了详细讨论,该概念允许一个解决方案存储大量的"like".你可以把它和这里的基本概念一起作为一种批量操作的方法.