该文档仅更新一次。猫鼬

时间:2019-04-29 14:18:22

标签: node.js mongodb mongoose

我正在通过数组中的 _id 查找文档。然后,我更改“余额”字段并保存文档。该操作执行了五次,但余额仅更改了一次。代码:

users.forEach(async(user) => {
        if (user.active) {

            /* SOME STUFF */

            const owner = await Owner.findById(user.owner)
            owner.balance = (owner.balance * 100 - 0.01 * 100) / 100
            await owner.save()
        }
    })

尝试过:

Owner.findById(user.owner).then((owner) => {
   owner.balance = (owner.balance * 100 - 0.01 * 100) / 100
   owner.save(err => {
     if(err) console.log(err)   
   })
})

也尝试过:

owner.markModified(balance);

所有者架构:

const ownerSchema = new Schema({
    balance: {
        type: Number
    }
});

Test output from console 在此图片上,您可以看到测试输出。之前的余额为99.53。 因此,余额应为99.48,但应为99.52。

3 个答案:

答案 0 :(得分:0)

为什么不尝试

    Owner.findByIdAndUpdate()

它将通过ID查找所有者并更新它,从而缩短并改善了代码的版本(简洁)

答案 1 :(得分:0)

您可能期望在forEach()中一个一个地处理每个用户,但是这不会发生,而是宁愿同时运行。

要使代码运行才能执行的操作是使用for ... of,这将确保执行顺序。如下所示:

for(let user of users) {
    if (user.active) {
        /* SOME STUFF */
        const owner = await Owner.findById(user.owner)
        owner.balance = (owner.balance * 100 - 0.01 * 100) / 100
        await owner.save()
      }
}

答案 2 :(得分:0)

问题出在您使用forEach函数上。

当您在函数的前面编写async时,您基本上将其包装为一个Promise,这意味着它的返回值被更改为一个Promise。

forEach没有返回值,这意味着当您将其包装为一个承诺时,没有人正在等待该承诺,这会导致意外的行为。并且您的情况实际上确实更新了5次,但并不像您期望的那样同步。

我建议使用bluebird之类的库,因为它具有强大的功能,代码如下所示:

let Promise = require("bluebird")
....

let users = [user array];
await Promise.mapSeries(users, (user) => {
              if (user.active) {

            /* SOME STUFF */

            const owner = await Owner.findById(user.owner)
            owner.balance = (owner.balance * 100 - 0.01 * 100) / 100
            await owner.save()
        }
})

它现在可以根据需要运行。