所以我在 MongoDB (2.6.4) 中有一个查询,我试图在其中实现一个简单的 upvote/downvote 机制。当用户单击 upvote 时,我需要执行以下操作:

到目前为止,我形成的查询(不正确)是:

db.collection.aggregate([
{
    $project: {
        "_id" : ObjectId("53e4d45c198d7811248cefca"),
        "upvote": {
           "$cond":
            [
            {"$in": ["$upvote",1] },
            {"$pull": {"upvote" : 1}},
            {"$addToSet": {"upvote" : 1}, "$pull": {"downvote": 1}}
            ]
        }
    }
}
])
其中“1”是尝试投票的用户 ID。upvotedownvote 都是数组,它们分别包含已投赞成票和反对票的用户的用户 ID。
对于查询的输出,我只想要一个 bool 值: true 如果 $cond 评估为 true ,否则为 false

最佳答案

这不是实现赞成票和反对票的好方法。除了聚合框架不是以任何方式更新文档的机制之外,由于您想要实现的逻辑,您似乎倾向于认为它可能是一个解决方案。但聚合不更新。

你想要什么,我们称之为“问题”模式是这样的结构:

{
    "_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 AP I 进行操作(实际上可能是最好的方法),但它有其意义。第一个语句将只匹配当前用户在数组中记录了“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 },
    }
)

自然地,您可以看到简单地取消相关用户的任何“赞成/反对”的逻辑进展。如果您希望并公开客户端中的信息,不仅可以显示当前用户是否已经“赞成/反对”,而且还可以控制点击操作并消除不必要的请求,那么您也可以聪明一点。

关于mongodb - 如果不存在则插入,否则删除 MongoDB,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25421164/

10-11 04:59