【问题标题】:Mongoose: $inc increments the field by double the value specifiedMongoose:$inc 将字段增加指定值的两倍
【发布时间】:2020-09-14 12:54:49
【问题描述】:

我有一份文件:

{
    "_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”会呈现您知道的其他问题。

【问题讨论】:

  • 我的猜测是您正在调试服务器上的路由,并且由于添加了调试侦听器,它被调用了两次。语法是正确的,你只是更新被调用了两次。
  • 不,它只运行一次。

标签: node.js mongodb express mongoose


【解决方案1】:

它肯定被调用了两次。你可能认为它不是,但它是;)

您可以做的一件事是添加一个前提条件,这样它就不会同时更新两次。比如这样:

model.updateOne(
  {
    username: "Jamie",
    points: 25 // this will fail to match if the points change
  },
  { $inc: { points: 5 } }
)

那么问题来了,它怎么会在你不知情的情况下运行两次。您是否通过队列处理程序(例如 SQS)运行它?如果是这样,SQS 不保证单次交付,您必须确保您的代码是幂等的。与其他各种执行方法相同的故事。

您还如何调试它?需要更多代码和上下文来进一步提供帮助,但通常$inc 只会将值增加您指定的数字,因此您增加 5 并添加 10 强烈意味着它被调用了两次。

【讨论】:

    【解决方案2】:

    发现我正在混合等待和回调。 Await 仅在返回 promise 时起作用。所以我删除了回调。下面是正确的代码:

     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);
    
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-27
      • 2017-03-15
      • 2020-08-15
      • 2017-11-30
      • 1970-01-01
      • 2021-06-25
      • 2020-04-18
      相关资源
      最近更新 更多