Home > OS >  JavaScript - Async/Await - How to Return result from nested functions?
JavaScript - Async/Await - How to Return result from nested functions?

Time:08-08

I'm new to Node.js and having difficulty working with async/await model. The issue I'm having is with nested function calls returning data in an async/await method, I always get 'undefined'. My functions structure is like this:

const findCustomerOrder = async (id) => {
    const orders = await Order.find({custoemrId:id})
        .then(async (order) => {
            if(order)
                {
                  const products = await findProductsByOrderId(order._id)
                        .then(async (result) => {
                            for(const r in result){
                                console.log("Product ID: ", result._id);
                            }
                        });
                }
            else
                console.log("order not found");     

        });
}

const findProductsByOrderId = async (id) => {
    try{
        const products = await Products.find({orderId:id}, (error, data) => {
            if(error) console.log(error);
            else 
                return data;
        });
    }
    catch(err){
            return 'error!!';
    }
}

I understand that if the top-level call is async/await then all the nested calls should be awaited as well that I've tried to do.

What am I doing wrong here?

CodePudding user response:

Get rid of all the then, and also of the callback in the DB query. Use only await. It will make the whole code a lot easier to reason about and it should also solve your issue as part of the restructuring.

In the example below I also added a loop over the orders, because you are fetching all orders, as array, but then your code was behaving as if it got only one. I also fixed the products loop.

However, the way you fetch products doesn't seem to be right anyway, see my comment below. I didn't fix it because I don't know how your database structure looks, so I don't know what the right way would be.

async function findCustomerOrder (id) {
  const orders = await Order.find({ customerId: id })
  
  for (const order of orders) {
    console.log(`Order ID: ${order._id}`)
    
    const products = await findProductsByOrderId(order._id)
    for (const product of products) {
      console.log(`Product ID: ${product._id}`);
    }
  }
}

async function findProductsByOrderId (id) {
  // Note: I don't think this is right. It seems to find all
  // products with the given ID - which will always be one -
  // and that ID would be the _product_ ID and not the order ID.
  return await Products.find({ _id: id })
}

Preemptive comment reply: The return await is intentional, and this is why.

CodePudding user response:

You should remove the then and also the callback and you can do something like below

const findCustomerOrder = async(id) => {
  try {
    const orders = await Order.find({
      custoemrId: id
    });

    if (orders) {
      let promiseArray = [];
      orders.forEach(order => {
        promiseArray.push(findProductsByOrderId(order._id));
      });
      let results = await Promise.all(promiseArray);

      return results;
    }

    return "order not found";
  } catch (err) {
    throw err;
  }
}

const findProductsByOrderId = async(id) => {
  try {
    const products = await Products.find({
      _id: id
    });
    return products;
  } catch (err) {
    throw err;
  }
}

  • Related