Jelmer Overeem
Jelmer Overeem

Reputation: 419

Using async/await with for loop and mongodb

I want to send an order-confirmation email(with nodemailer) to customers when they finished the order.
In this confirmation email I want to insert some data from the buyed products.

I've used many async/await combinations but none of them succeeded.
The code I got for now:

async function getProductData(products) {
  let productsArray = products;
  try {
    let productsHtml = "";
    for await (const product of productsArray) { // loop through the products
      db.collection("collectionname").findOne(query, (err, data) => { // get data for every product
        if (err) console.log(err)
         else {
           let productHtml = `<p>productname: ${data.productname}</p>
                             <img src="${data.imageSrc}">`;
           productsHtml += productHtml; // add the product html string to productsHtml
         }
      })
    }
  } catch (error) {
    console.log(error);
  }
  return productsHtml; //return the productsHtml string. But it returns "", because it doesn't await the mongodb function
}

async function sendConfirmationMail() {
  let productsHtml = await getProductData(products); //"products" is an array

  //nodemailer code
  let transporter = nodemailer.createTransport({
    // configuration
  });

  let email = await transporter.sendMail({
    //email information
   html: `<p>Thank you for your order!</p>
          ${productsHtml}`;, // insert the html string for all products into the mail
  });
}

The problem is that the return statement in getProductData() fires before the for loop finishes. And then returns undefined.

Does anyone have tips on how I can implement async/await the correct way here?

Upvotes: 1

Views: 1975

Answers (1)

Jeremy Thille
Jeremy Thille

Reputation: 26360

You are not awaiting your database call. You are passing it a callback, so it does not return a Promise :

.findOne(query, (err, data) => {

This has a callback. You are passing it a function as second argument, that takes (err,data) as its own arguments. You need to remove this callback and use the async/await syntax with try/catch. Something like

const data = await db.collection("collectionname").findOne(query);

On the other hand you don't need to for await (const product of productsArray). You are iterating an array of static values, not an array of Promises. Remove this await.

Upvotes: 2

Related Questions