我正在学习mongodb并想知道我是否可以通过匹配值限制推送。
例如:
field1 = {
id:123,
title:123,
likes: [{by:1,type:'like'}, {by:2, type:'like'}]
}
我可以限制id
中的likes
推送吗?
答案 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只应用一次或根本不应用。
这是正确处理此类投票的基本模式,因为您保留每种投票类型的列表以及维护易于访问的计数。 "不喜欢"进程几乎与你需要检查的元素的逻辑相反,删除投票也有类似的条件。