【问题标题】:Mongoose Async find all and update for eachMongoose Async 查找所有并更新每个
【发布时间】:2019-10-23 21:45:37
【问题描述】:

我有小费游戏。游戏完成后,我从 mongoose db 中获取所有提示,然后使用 forEach 迭代这些提示。

对于这些提示中的每一个,我都会获取用户名并从猫鼬数据库加载用户以增加该用户的积分,然后将用户更改保存回数据库。

一个用户可以有多个小费。

Tips.find({...}).exec(function(err, gameTips) {

   gameTips.forEach(tip, i) => {

      User.findOne({
         username: tip.username
      }).exec(function(err, user) {

          user.points = user.points + 1;

          user.save(function(err) {
             console.log("Points were increased");
          });
      });
   });
}

现在我的问题是用户的 findOne 是在保存 prev 提示处理之前完成的。所以分数不会正确增加。

用户:testUser 有 4 个提示 | 预期:testUser.points = 4; | 当前:testUser.points = 2;

是否有可能异步执行此操作,以便所有用户的查找和保存将一个接一个地完成,以便每次我这样做:

user.points = user.points +1;

我会在增加之前获得更新的积分吗?


编辑

感谢您的提示。我已经尝试采用它,我的代码现在是:

async function updateUserPoints(schedule) {
try {
    console.log("Load Schedules");
    const scheduleTips = await Tip.find({
        scheduleId: schedule._id,
        season: schedule.season
    });

    console.log(scheduleTips);

    if (scheduleTips.length) {

        for (const scheduleTip of scheduleTips) {
            console.log("Load User for scheduleTip: " + scheduleTip.tip);
            let user = await User.findOne({
                username: scheduleTip.username
            })

            console.log(user);
            if (user) {
                const winner = calculateWinner(schedule);
                const points = calculatePoints(scheduleTip, winner);

                console.log("WINNER: " + winner);
                console.log("POINTS: " + points);

                user.tippspiel.overallPoints = user.tippspiel.overallPoints + points;
                user.tippspiel.seasonPoints = user.tippspiel.seasonPoints + points;
                user.tippspiel.gameWeekPoints = user.tippspiel.gameWeekPoints + points;

                await user.update({ username: scheduleTip.username }, { $inc: { "tippspiel.overallPoints": points } }, function(err) {
                    if (err) {
                        logger.error("[Tippspiel-User]: " + err);
                    } else {
                        logger.info("[Tippspiel-User]: User tippspiel points were updated.");
                    }
                });
            }
        }
    }

} catch (err) {
    console.error(err);
}
}

function calculateWinner(schedule) {
let winner;

if (schedule.homeScore > schedule.awayScore) {
    //Home wins
    winner = "home";
} else if (schedule.homeScore < schedule.awayScore) {
    //Away wins
    winner = "away";
} else if (schedule.homeScore == schedule.awayScore) {
    //Tie/Draw
    winner = "draw";
}
return winner;

}

function calculatePoints(scheduleTip, winner) {
const POINTS_CORRECT_WINNER = settings.tippspiel.pointsCorrectWinner;
const POINTS_CORRECT_DRAW = settings.tippspiel.pointsCorrectDraw;
//If user has tipped correct
if (scheduleTip.tip === winner) {
    let points = 0;

    if ((scheduleTip.tip === "home") || (scheduleTip.tip === "away")) {
        points = points + POINTS_CORRECT_WINNER;

    } else if (scheduleTip.tip === "draw") {
        points = points + POINTS_CORRECT_DRAW;
    }

    return points;
} else {
    return 0;
}
}

我现在就测试一下:)

【问题讨论】:

    标签: javascript node.js asynchronous mongoose async-await


    【解决方案1】:

    您不能像在forEach 中那样使用异步代码,它不会产生预期的结果。您可以使用 for ofasync await 以获得更简洁的代码:

     async function updateTips() {
     try {
        const tips = await Tips.find({condition: 'condition'})
        if (tips.length) { // check for empty result
            for (const tip of tips) {
                let user = await User.findOne({ username: tip.username })
                if (user) {
                    user.points = user.points + 1
                    await user.save()
                    console.log('Points were increased')
                }
            }
        }
     } catch (err) {
         // handle errors here
     }
    }
    
    updateTips()
    

    【讨论】:

    • 经过 2 天的搜索,您的答案对我来说是正确的!非常感谢!
    【解决方案2】:

    发生的情况是您使用之前的分数来计算下一个分数,而不是使用 mongoDB $inc 运算符

    使用回调的选项1,丑陋且根本不可读

    Tips.find({})
      .exec(function(err, gameTips) {
        if(err) {
          console.error(err);
          return;
        }
        gameTips.forEach(tip => {
          User.findOneAndUpdate(
            { username: tip.username },
            { $inc: { points: tip.points }}
          ).exec(function(err, user) {
            if(err) {
              console.error(err);
              return;
            }
            console.log("Points were increased");
          })
        })
      })
    

    选项 2 使用 PromisesPromise.all() 更易读

    Tips.find({})
      .then(gameTips => Promise.all(gameTips.map(tip => User.updateOne(
        { username: tip.username},
        { $inc: { points: tip.points } }
      )))
      .then(() => {
        console.log("Points were increased");
      })
      .catch(console.error)
    

    使用async / await的选项3,我最喜欢的,简单易读

    async function run() {
      try {
        const gameTips = await Tips.find({});
        await Promise.all(gameTips.map(tip => User.updateOne(
          { username: tip.username},
          { $inc: { points: tip.points } }
        )));
        console.log("Points were increased");
      } catch (err) {
        console.error(err);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-08-05
      • 1970-01-01
      • 2020-12-04
      • 2019-12-11
      • 2014-11-27
      • 2016-10-23
      • 1970-01-01
      • 1970-01-01
      • 2021-02-21
      相关资源
      最近更新 更多