如何限制mongodb的$ push?

时间:2015-07-31 00:05:24

标签: mongodb push mongodb-query

我正在学习mongodb并想知道我是否可以通过匹配值限制推送。

例如:

field1 = {
 id:123,
 title:123,
 likes: [{by:1,type:'like'}, {by:2, type:'like'}]
}

我可以限制id中的likes推送吗?

1 个答案:

答案 0 :(得分:1)

你可能已经尝试过的是$addToSet运算符,但后来发现它不适合这里作为" id"的组合。和"键入"可能会有所不同。例如,你不想要的是相同的" id"两种类型的价值"喜欢"并且"不喜欢"。

然而,这是典型的"投票"模型,目前的结构并不是最好的。一个更好的模型是这样的,基本字段就是例如:

{
    "_id": 123,
    "likeCount": 2,
    "dislikeCount": 0,
    "likes": [456,789]
    "dislikes": []
}

具有单独的数组对于原子更新过程很重要,因为您不能同时从数组中$pull$push。但更重要的是,它重新强化了保持"计数"值,因为这对于简单查询作为排序非常有用,而不是计算数组长度。

为了发布"喜欢"对于您不希望在数组中复制的用户,$addToSet运算符仍然不是最佳运算符,尽管这些值现在是真正唯一的。你想要反对"计数"同样,请在更新中为查询添加条件:

db.collection.update(
    { "_id": 123, "likes": { "$ne": 456 } },
    { 
        "$push": { "likes": 456 },
        "$inc": { "likeCount": 1 }            
    }
)

这样,如果用户已经投票他们的"喜欢"然后不仅没有添加任何内容,而且还有#34;计数"保持在正确的总数。基本上没有满足更新的查询条件,因为数组中的元素已经匹配该值。所以文档不匹配,没有更新。

这是一个很好的方法,但我们可以做得更好。如果用户已发布到"不喜欢"该怎么办?现在他们的想法改变为"喜欢"代替?你真正需要的是"两个"更新语句以涵盖可能的条件,这是Bulk Operations API所在的位置,以便在单个请求中处理该逻辑:

var bulk = db.collection.initializeOrderedBulkOp();

// match and update where a dislike is present
bulk.find({ 
    "_id": 123, 
    "likes": { "$ne": 456 },
    "dislikes": 456
}).updateOne({
    "$push": { "likes": 456 },
    "$pull": { "dislikes": 456 }
    "$inc": {
        "likeCount": 1,
        "dislikeCount": -1
    }
});

// match and update where no dislike exists
bulk.find({ 
    "_id": 123, 
    "likes": { "$ne": 456 },
    "dislikes": { "$ne": 456 }
}).updateOne({
    "$push": { "likes": 456 },
    "$inc": { "likeCount": 1 }
});

// Send requests to server and respond
bulk.execute();

在这种情况下,如果第一个语句不匹配,因为没有不喜欢,那么什么都不会更新,但如果不喜欢,那么将进行正确的调整。

对于第二个请求,如果dislikes数组中没有任何内容可以匹配,并且在likes数组中也没有匹配项,则会应用此请求。因此,这将适用于新的投票,也不会与之前的声明冲突。尽管有两个陈述,但根据州的情况,upadte只应用一次或根本不应用。

这是正确处理此类投票的基本模式,因为您保留每种投票类型的列表以及维护易于访问的计数。 "不喜欢"进程几乎与你需要检查的元素的逻辑相反,删除投票也有类似的条件。