1

I try to make a list with products that I send to the client, but the res.send gets executed before the loop has finished. Do you have any suggestions? Async/await doesn't seem to work.

Here is my code:

const Outfits = require("../models/Outfits");
const Products = require("../models/Products");

module.exports = (req, res) => {
    Outfits.find({ outfitId: req.params.id }, async (error1, result) => {
        if (error1) {
            res.status(400).json({
                status: "fail",
            });
        } else {
            let productIds = result[0].productIds;
            let productList = [];
            for (let i = 0; i < productIds.length; i++) {
                await Products.find({ id: productIds[i] })
                    .then((product) => {
                        console.log(product);
                        productList.push(product);
                    })
                    .catch((error2) => {
                        res.status(400).json({
                            status: "fail",
                        });
                    });
            }
            console.log(productList);
            res.status(200).json({
                status: "success",
                body: productList,
            });
        }
    });
};

Thank you very much!

Youssouf Oumar
  • 29,373
  • 11
  • 46
  • 65
jansemrau
  • 231
  • 3
  • 11
  • few things, `map` doesn't work with `await`, and if it did, you're not returning anything from the `productIds.map` loop. – Phix Feb 16 '22 at 18:02
  • I changed the code. The console.log(product) shows the item but the console.log(products) and the products in the res is undefined. The console.log(products) gets executed before console.log(product) – jansemrau Feb 16 '22 at 18:07
  • I think the issue might be with `Products.find`. Are you sure that the method is not async? – Harshil Laheri Feb 16 '22 at 18:07
  • Does this answer your question? [How to return the response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – Heretic Monkey Feb 16 '22 at 18:09
  • 1
    @HarshilLaheri when I make it async, I get the error "const err = new MongooseError('Query was already executed: ' + str);" – jansemrau Feb 16 '22 at 18:14
  • Ohh, didn't realise that it is a Mongoose model. In that case it is definitely async. You can use await on that. See https://stackoverflow.com/questions/46457071/using-mongoose-promises-with-async-await . This will probably work – Harshil Laheri Feb 16 '22 at 18:17
  • @HarshilLaheri I changed to that but the res.send gets executed before – jansemrau Feb 16 '22 at 18:21
  • Can you share the updated code? You might need to change the `.map` to a for loop and then call `await` on `Products.find`. That should work. – Harshil Laheri Feb 16 '22 at 18:25
  • so, now it works. I changed the code in my question. Thank you very much! – jansemrau Feb 16 '22 at 18:33
  • Saw the update, I'm still not sure if this is the right way to do it. Posting an answer with the correct way to use await on .find. – Harshil Laheri Feb 16 '22 at 18:38

3 Answers3

2

In order to have multiple asynchronous tasks executed at once, a cleaner way is to use a Promise.all and pass an array of your asynchronous tasks. Like so:

const Outfits = require("../models/Outfits");
const Products = require("../models/Products");

module.exports = (req, res) => {
    Outfits.find({ outfitId: req.params.id }, async (error1, result) => {
        if (error1) {
            res.status(400).json({
                status: "fail",
            });
        } else {
            let productIds = result[0].productIds;
            
            //
            const productList = await Promise.all(
                 productIds.map((id) => Products.findById(id))
            );
           
            console.log(productList);
            res.status(200).json({
                status: "success",
                body: productList,
            });
        }
    });
};
Youssouf Oumar
  • 29,373
  • 11
  • 46
  • 65
1

You need to call await on the Products.find function like this

for (let i = 0; i < productIds.length; i++) {
  try {
    const product = await Products.find({ id: productIds[i] }).exec()
    console.log(product);
    productList.push(product);
  } catch (error) {
    res.status(400).json({
      status: "fail",
    });
  }
}
1

Do you have any suggestions? Async/await doesn't seem to work

The async/await in your code does not work it is because of the function mongoose gives you.

  1. callback style

    // finds the outfit and passes the outfit to the callback

    Outfits.find({ outfitId: req.params.id }, async (error1, outfit) => {

    // your other logic

    })

  2. async/await style

    // finds the outfit and returns

    const outfit = await Outfits.find({outfitId: req.params.id }).exec();

Assuming you retrieve array of product id this way

let productIds = result[0].productIds;

const products = await Promise.all(

productIds.map((productId)=>{

   return Products.findById(productId)

}

)

This should retrieve you the list of products

This is my first time answering a question hence the try hard answer haha :).

Dharman
  • 30,962
  • 25
  • 85
  • 135
Deep Grg
  • 116
  • 1
  • 3