我没有小费游戏。游戏结束后,我会从猫鼬数据库中获得所有提示,然后使用forEach遍历这些提示。
对于每一个提示,我都获得了用户名并从mongoose db加载用户以增加该用户的积分,然后保存该用户,将其更改回db。
一个用户可以拥有多个提示。
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操作。因此,积分将无法正确增加。
用户: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;
}
}
我现在将对其进行测试:)
答案 0 :(得分:1)
您不能像在forEach
中那样使用异步代码,它不会产生预期的结果。您可以将for of
与async 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()
答案 1 :(得分:1)
发生的事情是,您使用先前的点来计算下一个分数,而不是使用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");
})
})
})
使用Promises的选项2,很多使用Promise.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)
选项3使用async
/ await
,我最喜欢的,简单易读的
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);
}
}