The variables I updated in my forEach, return to their original value

时间:2019-06-01 14:07:05

标签: javascript node.js mongodb foreach

I am trying to query, that would get all of the earning and withdrawal amount and sum, but somehow after the forEach loop is done and exits, all of the updated values I placed in a variable return to their original values.

  var withdrawbalance = 0;
  var totalearning = 0;

  userplans.forEach((up) => {
    DepositEarning.findOne({deposit: up.deposit._id})
      .then(depositearning => {
        withdrawbalance += parseInt(depositearning.WithdrawableBalance, 10);
      });
    Earning.findOne({deposit: up.deposit._id})
      .then(earnings => {
        totalearning += parseInt(earnings.Earning, 10);
    });
  })

  console.log(withdrawbalance);
  console.log(totalearning);

5 个答案:

答案 0 :(得分:4)

您正在forEach中运行异步代码,并且forEach不会等到异步代码完成,为此,必须用等待的原语包装异步代码,像这样

await Promise.all(userplans.map(async (up) => {
    await DepositEarning.findOne({deposit: up.deposit._id})
      .then(depositearning => {
        withdrawbalance += parseInt(depositearning.WithdrawableBalance, 10);
      });
    await Earning.findOne({deposit: up.deposit._id})
      .then(earnings => {
        totalearning += parseInt(earnings.Earning, 10);
    });
  }))

答案 1 :(得分:0)

我认为原因可能是DepositEarning.findOne()和Earning.findOne()都是异步函数。这意味着它们不会立即返回值,因此循环后您的变量仍然相同。

答案 2 :(得分:0)

这里是一种实用的方法,可消除循环内部的突变副作用。为此,您需要一个支持Object Rest传播的引擎:

async function calculate(userplans) {
    const add = (acc, n) => acc + n;
    const flatten = (acc, e) => ({
        depositEarnings: [...acc.depositEarnings, e.depositEarnings], 
        earnings: [...acc.earnings, e.earnings]
    });

    const {depositEarnings, earnings} = (await Promise.all(userplans
          .map(async (up) => ({
              depositEarnings: await DepositEarning.findOne({deposit: up.deposit._id}),
              earnings: await Earning.findOne({deposit: up.deposit._id})
}))))
          .reduce(flatten, {depositEarnings: [], earnings: []});

    const withdrawalBalance = depositEarnings
          .map(d => parseInt(d.WithdrawableBalance, 10))
          .reduce(add, 0);
    const totalEarning = earnings
          .map(e => parseInt(e.Earning, 10))
          .reduce(add, 0);

    console.log(withdrawalBalance);
    console.log(totalEarning);
}

答案 3 :(得分:0)

只需加上我的两分钱,

正如其他答案所述,您的foreach循环正在使用异步代码。它正在使用不属于Js的某些API。

将调用推送到调用堆栈,然后将其从调用堆栈中删除。因为现在该工作将由API处理。呼叫

console.log(withdrawbalance); console.log(totalearning);

被添加到调用堆栈中,现在的值是什么? 0 0。

API完成工作后,将在task queue中添加函数,然后event loop将检查调用堆栈是否为空。由于现在为空,因此将函数添加到调用堆栈中。

然后运行。然后您将获得withdrawbalance and totalearning值的真实值。

答案 4 :(得分:-1)

forEach is asynchronous. So the console.log runs before your mutation loop. You can make it synchronous by using map, but even then - you have asynchronous calls inside it. You will need to flatten it further - probably by doing Promise.all on a map, then reducing the output of that.