所以我在MongoDB(2.6.4)中有一个查询,我试图实现一个简单的upvote / downvote机制。当用户点击upvote时,我需要执行以下操作:
如果用户已经投票,则删除upvote。
否则,如果没有被用户投票,则添加upvote并删除downvote(如果存在)。
到目前为止,我的查询形成(不正确)是:
db.collection.aggregate([
{
$project: {
"_id" : ObjectId("53e4d45c198d7811248cefca"),
"upvote": {
"$cond":
[
{"$in": ["$upvote",1] },
{"$pull": {"upvote" : 1}},
{"$addToSet": {"upvote" : 1}, "$pull": {"downvote": 1}}
]
}
}
}
])
其中' 1'是尝试upvote的用户ID。
upvote
和downvote
都是包含分别有upvoted和downvoted的userIds的数组。
对于查询的输出,我只想要一个bool值:true
如果$cond
评估为true
,则false
。
答案 0 :(得分:4)
这不是实施向上投票和投票的好方法。除了聚合框架不是以任何方式更新文档的机制之外,由于您希望实现的逻辑,您似乎倾向于认为它可能是一种解决方案。但聚合不会更新。
你想要什么,我们称之为“问题”架构是这样的结构:
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"upvoted": [],
"downvoted": [],
"upvoteCount": 0,
"downvoteCount": 0
}
这可以很好地处理原子更新,并实际上同时为您提供有关该对象的一些有状态信息。
对于“upvoted”和“downvoted”数组,我们将考虑“用户”投票具有类似的唯一ObjectId值。所以我们要做的是从任一数组中$push
或$pull
,并且还“递增/递减”计数器值以及每个操作。
以下是这对于upvote的工作原理:
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 AP我做(也许是最好的方式),但它有一个重点。第一个语句仅匹配当前用户在阵列中记录“downvote”的文档。因为它,我们已经将该用户id值“推送”到“downvotes”数组。如果不存在则不进行更新。但是你们都可以从各自的数组推送和拉出,同时也“增加/减少”计数器字段。
第二个陈述只会匹配第一个没有的东西,你做了一个公平的评估,现在你不需要触及“downvotes”,只需处理upvote字段。在这两种情况下,安全的做法是确保主要条件是“upvoted”数组中不存在当前用户id值。
对于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 },
}
)
当然,您可以看到逻辑进展只是为相关用户取消任何“upvote / downvote”。如果您想要并在客户端公开信息,您不仅可以显示当前用户是否已经“upvoted / downvoted”,还可以控制点击操作并消除不必要的请求。