这不是一个好的实现赞和踩的方式。除了聚合框架不是任何更新文档的机制之外,你似乎因为你想要实现的逻辑而倾向于认为它可能是一个解决方案。但聚合操作并不会进行更新。
在你的“问题”模式中,你需要像这样的结构:
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"upvoted": [],
"downvoted": [],
"upvoteCount": 0,
"downvoteCount": 0
}
这是可以与原子更新很好配合使用的东西,并且可以同时为对象提供一些有状态的信息。
对于"upvoted"和"downvoted"数组,我们将考虑"users"投票具有类似的唯一ObjectId值。因此,我们要做的是从任一数组中$push
或$pull
,并在每个操作中同时"增加/减少"计数器值。
以下是点赞的工作方式:
db.questions.update(
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"upvoted": { "$ne": ObjectId("53f51c0a4ffa9b02cf01c075") }
"downvoted": ObjectId("53f51c0a4ffa9b02cf01c075")
},
{
"$push": { "upvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
"$inc": { "upvoteCount": 1, "downvoteCount": -1 },
"$pull": { "downvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
}
)
db.questions.update(
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"upvoted": { "$ne": ObjectId("53f51c0a4ffa9b02cf01c075") }
},
{
"$push": { "upvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
"$inc": { "upvoteCount": 1 },
}
)
实际上这是两个操作,你可以通过
Bulk operations API来完成(可能是最好的方式),但这有其重要性。第一个语句只会匹配当前用户在数组中记录了“downvote”的文档。因为我们已经将该用户id值推送到“downvotes”数组中,所以如果它不在那里,则不进行更新。但你需要同时从相应的数组中推送和拉取,并且同时“增加/减少”计数字段。
对于第二个语句,它只会匹配第一个语句没有匹配到的内容,你可以公正地评估现在你不需要触及“downvotes”,而只需处理upvote字段。在两种情况下,安全的做法是确保主条件是当前用户id值不存在于“upvoted”数组中。
对于downvotes,字段仅相反:
db.questions.update(
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"downvoted": { "$ne": ObjectId("53f51c0a4ffa9b02cf01c075") }
"upvoted": ObjectId("53f51c0a4ffa9b02cf01c075")
},
{
"$pull": { "upvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
"$inc": { "upvoteCount": -1, "downvoteCount": 1 },
"$push": { "downvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
}
)
db.questions.update(
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"downvoted": { "$ne": ObjectId("53f51c0a4ffa9b02cf01c075") }
},
{
"$push": { "downvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
"$inc": { "downvoteCount": 1 },
}
)
自然而然,您可以看到逻辑进展,只需取消有关用户的任何“赞成/反对”即可。如果您愿意,您还可以在客户端中智能处理此信息,不仅显示当前用户是否已经“赞成/反对”,还可以控制单击操作并消除不必要的请求。