【问题标题】:async problem array empty nodejs mongoose异步问题数组空 nodejs mongoose
【发布时间】:2020-10-20 11:12:47
【问题描述】:

我想从 req.body 中的 ID 数组中获取每种产品的名称和价格,并将其保存在新模型中(付款),为此我遍历每种产品并查找其db (Product.findById) 中的 id 并将我需要的东西(名称和价格)保存为 arrayProducts 中的一个对象,但是 newPayment 是在 arrayProducts 完成填充之前创建的,我将它创建为空,因为我可以这样做newPayment 是在 forEach 产品完成后创建的?

router.post('/new/payment', async (req, res) => {

    const date = Date.now();

    const { amount, clientId, products, services, officeId } = req.body;

    var arrayProducts = [];

    products.forEach(function (product) {
        var productFound = {};

        Product.findById(product, function (err, result) {
            if (err) {
                res.status(404).send({ error: "Oh uh, something went wrong", err: err });
            }
            else {
                productFound = { name: result.name, price: result.price };
                arrayProducts.push(productFound);
                console.log(arrayProducts);
            }
        })
    });
    console.log(arrayProducts);

    const newPayment = new Payment({ amount, clientId, products: arrayProducts, services, officeId, date });
    await newPayment.save((err) => {
        if (err) {
            res.status(404).send({ error: "Oh uh, something went wrong", err: err });
        }
        else {
            res.status(201).send({ status: "Payment successful", id: newPayment._id });
        }

    });;
});

【问题讨论】:

  • 您需要阅读有关 node.js 中的非阻塞、异步操作的信息。你的Product.findById() 是非阻塞和异步的,这意味着它的回调在你的整个路由处理程序完成执行之后被调用很长时间,当然在console.log(arrayProducts); 和之后的所有代码之后。
  • 您可能应该做的是将products.forEach() 更改为for (let product of products) { ... },为您的数据库使用Promise 接口并在该promise 上使用await,这样您就可以正确排序您的操作以及何时执行最后一个操作完成,然后执行其余代码。或者,您可以收集所有的 Promise 并使用 Promise.all() 跟踪它们何时完成。
  • 仅供参考,如果您在代码的各个部分(循环前、循环内和循环后)放置独特的 console.log() 语句,您将看到有缺陷的执行顺序。作为基本调试步骤,您应该学习如何自己做这件事。

标签: node.js mongoose async-await


【解决方案1】:

您需要阅读有关 node.js 中的非阻塞、异步操作的信息。你的 Product.findById() 是非阻塞和异步的,这意味着它的回调在你的整个路由处理程序完成执行之后被调用 LONG,当然在 console.log(arrayProducts); 和之后的所有代码之后。

既然你想从你的数据库中做 N 个请求,并且你只想知道它们什么时候完成,最有效的方法是使用你的数据库的 Promise 接口,从所有的 Promise 中收集一个数组数据库操作,然后使用Promise.all() 通知它们何时完成。

这是我的建议:

router.post('/new/payment', async (req, res) => {

    const date = Date.now();
    const { amount, clientId, products, services, officeId } = req.body;
    try {
        const allProducts = await Promise.all(products.map(async (product) => {
            const item = await Product.findById(product);
            return {name: item.name, price: item.price};
        }));
        const newPayment = new Payment({ amount, clientId, products: allProducts, services, officeId, date });
        await newPayment.save();
        res.status(201).send({ status: "Payment successful", id: newPayment._id });
    } catch(err) {
        res.status(404).send({ error: "Oh uh, something went wrong", err: err });
    }
});

此代码中缺少的其他内容是:

  1. 验证amount, clientId, products, services, officeId 的输入值,并在其中任何一个缺失或无效时发送相应的错误。
  2. 如果指定的产品在您的数据库中找不到,该怎么办?
  3. 如果您遇到数据库错误(可能是 500 错误),则 404 错误可能不合适。

【讨论】:

  • @nahuelmuñoz - 你还在这里吗?我正试图教你如何在nodejs中编写这种类型的代码,但你似乎消失了。
猜你喜欢
  • 2021-07-21
  • 2017-09-05
  • 2015-02-19
  • 2013-04-29
  • 1970-01-01
  • 2019-11-23
  • 2017-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多