如果不存在则插入,否则删除MongoDB

时间:2014-08-21 08:03:02

标签: mongodb mongodb-query

所以我在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。 upvotedownvote都是包含分别有upvoted和downvoted的userIds的数组。

对于查询的输出,我只想要一个bool值:true如果$cond评估为true,则false

1 个答案:

答案 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”,还可以控制点击操作并消除不必要的请求。