如何在 mongodb 中限制 $push?
how to restrict $push in mongodb?
我正在学习mongodb,想知道是否可以通过匹配值来限制推送。
例如:
field1 = {
id:123,
title:123,
likes: [{by:1,type:'like'}, {by:2, type:'like'}]
}
我可以在 likes
中限制 id
的推送吗?
您可能已经尝试过 $addToSet
运算符,但后来发现它不适合这里的情况,因为 "id" 和 "type" 的组合可能会有所不同。例如,您不想要的是具有 "like" 和 "dislike".
这两种类型的相同 "id" 值
然而,这是一个典型的"voting"模型,目前的结构并不是最好的。一个更好的模型是这样的,例如基本字段:
{
"_id": 123,
"likeCount": 2,
"dislikeCount": 0,
"likes": [456,789]
"dislikes": []
}
拥有单独的数组对于原子更新过程很重要,因为您不能 $pull
and $push
来自一个数组。但不仅如此,因为它加强了保持 "count" 值背后的逻辑,因为这对于简单查询很有用,因为排序而不是计算数组长度。
为了 post 为您不想在数组中重复的用户提供 "like",尽管有这些值,$addToSet
运算符仍然不是最佳运算符现在是真正独一无二的。您还想限制 "count",因此将条件添加到更新中的查询:
db.collection.update(
{ "_id": 123, "likes": { "$ne": 456 } },
{
"$push": { "likes": 456 },
"$inc": { "likeCount": 1 }
}
)
这样一来,如果用户已经为他们的 "like" 投票,那么不仅不会添加任何内容,而且 "count" 也会保持正确的总数。基本上不满足更新的查询条件,因为数组中已经有一个元素匹配该值。所以文档不匹配,没有任何更新。
这是一个很好的方法,但我们可以做得更好。如果用户已经 post 改为 "dislike" 并且现在改变主意改为 "like" 怎么办?您真正需要的是 "two" 更新语句来涵盖可能的条件,这就是 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 只应用一次或根本不应用。
这是正确处理此类投票的基本模式,因为您保留每种投票类型的列表并维护计数以便于访问。 "dislikes" 过程几乎与您需要检查的元素的逻辑相反,删除选票也有类似的条件。
我正在学习mongodb,想知道是否可以通过匹配值来限制推送。
例如:
field1 = {
id:123,
title:123,
likes: [{by:1,type:'like'}, {by:2, type:'like'}]
}
我可以在 likes
中限制 id
的推送吗?
您可能已经尝试过 $addToSet
运算符,但后来发现它不适合这里的情况,因为 "id" 和 "type" 的组合可能会有所不同。例如,您不想要的是具有 "like" 和 "dislike".
然而,这是一个典型的"voting"模型,目前的结构并不是最好的。一个更好的模型是这样的,例如基本字段:
{
"_id": 123,
"likeCount": 2,
"dislikeCount": 0,
"likes": [456,789]
"dislikes": []
}
拥有单独的数组对于原子更新过程很重要,因为您不能 $pull
and $push
来自一个数组。但不仅如此,因为它加强了保持 "count" 值背后的逻辑,因为这对于简单查询很有用,因为排序而不是计算数组长度。
为了 post 为您不想在数组中重复的用户提供 "like",尽管有这些值,$addToSet
运算符仍然不是最佳运算符现在是真正独一无二的。您还想限制 "count",因此将条件添加到更新中的查询:
db.collection.update(
{ "_id": 123, "likes": { "$ne": 456 } },
{
"$push": { "likes": 456 },
"$inc": { "likeCount": 1 }
}
)
这样一来,如果用户已经为他们的 "like" 投票,那么不仅不会添加任何内容,而且 "count" 也会保持正确的总数。基本上不满足更新的查询条件,因为数组中已经有一个元素匹配该值。所以文档不匹配,没有任何更新。
这是一个很好的方法,但我们可以做得更好。如果用户已经 post 改为 "dislike" 并且现在改变主意改为 "like" 怎么办?您真正需要的是 "two" 更新语句来涵盖可能的条件,这就是 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 只应用一次或根本不应用。
这是正确处理此类投票的基本模式,因为您保留每种投票类型的列表并维护计数以便于访问。 "dislikes" 过程几乎与您需要检查的元素的逻辑相反,删除选票也有类似的条件。