我有一个文件:
{
"_id" : "5ec8f4454868d203e8e624a3",
"username" : "Jamie",
"points" : 25,
}
我正在使用$ inc来增加“点”:
model.updateOne({username: "Jamie"},{$inc:{points:5}})
结果如下:
{
"_id" : "5ec8f4454868d203e8e624a3",
"username" : "Jamie",
"points" : 35,
}
知道为什么它要增加两倍于指定值吗?
这是实际的代码:
app.post("/signup", function(req, resp){
var parent_id;
globalvarCollection.findOne({serial:1}, 'current_level', function(doc){
try{
current_level=doc.current_level;
userCollection.countDocuments({level:current_level}, function(doc2){
userCollection.findOne({level:current_level-1, ttl_chldrn:{$lt:6}}, 'ref_id', function(doc3){
parent_id=doc3.ref_id;
userCollection.register({username:req.body.username,
level:current_level,
parent_id: parent_id,
ref_id:"REF"+create_ref_id(),
ttl_chldrn:0,
points:0,
pnts_rdmd_till_date: 0,
pnts_rdmd_this_month: 0 ,
jng_date: Date.now(),
}, req.body.password, async function(err, newDoc){
if(err){
resp.render("signup", {signupError:"Server error. Please try later."});
}
else{
currentUser=newDoc;
passport.authenticate("local")(req, resp, async function(){
resp.redirect("/userprofile");
//interestingly, $inc is working as expected here:
userCollection.updateOne({ref_id:parent_id}, {$inc:{ttl_chldrn: 1}}, async function(){
var rem_points=20
var ref_id=parent_id;
for(let CL=current_level-1; CL>=current_level-4; CL--){
//facing the issue here:
await userCollection.findOneAndUpdate({ref_id: ref_id, level:CL},{$inc:{points:4}}, function(errDoc1, doc1){
if (!errDoc1){
ref_id=doc1.parent_id;
rem_pts=rem_pts-4;
}
});
}
//facing the issue here as well:
await userCollection.updateOne({username: "Prince"},{$inc:{points:rem_pts}});
});
});
}
});
});
});
}
catch(err){
resp.render("signup", {signupError:"Server error. Please try later."});
}
});
});
几乎每个步骤都在使用console.log(在此省略)进行调试,但我看不到任何查询运行两次。尽管我怀疑这可能是async / await问题,因为在删除“ await”时$ inc可以按预期工作,但是随后删除“ await”会导致您知道其他问题。
答案 0 :(得分:0)
它肯定被两次叫过。您可能会认为不是,但是;)
您可以做的一件事就是添加一个前提条件,这样它就不会同时更新两次。像这样:
model.updateOne(
{
username: "Jamie",
points: 25 // this will fail to match if the points change
},
{ $inc: { points: 5 } }
)
然后的问题是,它如何在您不知道的情况下运行两次。您是否通过诸如SQS之类的队列处理程序运行它?如果是这样,SQS不保证单次交付,您必须确保代码是幂等的。同样的故事,还有其他各种执行方法。
您还如何调试它?需要更多的代码和上下文来进一步提供帮助,但通常$inc
只会根据您指定的数字增加该值,因此让您增加5并加上10会强烈暗示它被调用了两次。
答案 1 :(得分:0)
发现我正在将等待与回调混合在一起。等待仅在返回承诺时有效。所以我删除了回调。下面是正确的代码:
var rem_points=20
var ref_id=parent_id;
for(let CL=current_level-1; CL>=current_level-4; CL--){
const findAndUpdateQuery=await userCollection.findOneAndUpdate({ref_id: ref_id, level:CL},{$inc:{points:4}}).exec()
ref_id=findAndUpdateQuery.parent_id;
rem_pts=rem_pts-4;
}
const updateQuery=await userCollection.updateOne({username: "Prince"},{$inc:{points:rem_pts}}).exec();
console.log("modified docs: "+updateQuery.nModified);