无论您如何构建整个文档,您基本上都需要两件事。这基本上是一个“计数”和已经发布“喜欢”的人的“列表”的属性,以确保没有提交重复。这是一个基本结构:
{
"_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”选择要更新的文档之外,另一个重要的事情是检查“likes”数组以确保当前投票用户不在其中。
相反的情况或“删除”“喜欢”也是如此:
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 次“点赞”,则不能单独使用它。有一个称为“桶”的概念,在此示例中对Hybrid Schema design 进行了一些详细讨论,它允许一种解决方案来存储大量“喜欢”。您可以将其与此处的基本概念一起使用,作为批量执行此操作的一种方式。