Woppi
Woppi

Reputation: 5451

How to properly implement mongodb async/await inside a promise?

I've read that having an async inside a Promise is anti-pattern for async/await. The code below works, but I am curious how else to achieve the same result without having async in Promise.

If I remove it, the linter would tell how I can't use await in my mongodb query. If I remove the await in the mongodb query, then it wouldn't wait for the result.

export const getEmployees = (companyId) => {
  return new Promise(async (resolve, reject) => {
    const employees = await Employees.find(
      { companyId },
    );

    // other logic here...

    resolve({
      employees,
    });
  });

Thanks.

Upvotes: 2

Views: 2952

Answers (2)

CertainPerformance
CertainPerformance

Reputation: 371193

async functions automatically return Promises already, which resolve with whatever expression is eventually returned. Simply make getEmployees an async function:

export const getEmployees = async (companyId) => {
  const employees = await Employees.find(
    { companyId },
  );

  // other logic here...

  return { employees };
};

(but make sure to catch in the consumer of getEmployees just in case there's an error)

Upvotes: 4

Moshe Binieli
Moshe Binieli

Reputation: 461

As @CertainPerformance answered, that is perfect way to retrieve data from mongoDB using async/await, I would like to add some more information about how to handle errors in this case for correctness of the system, and better error handle to return better status to the client about his request.

I'd say it , you usually want to catch all exceptions from async/await call.

try {
    const employees = await Employees.find({
        companyId
    });
    // You can add more logic here before return the data.
    return {
        employees
    };
} catch (error) {
    console.error(error);
}

Now let's check the ways we can handle our errors that might occur.

  1. Handle error inside error scope.
  2. Assign a default value to the variable in the catch block.
  3. Inspect error instance and act accordingly.

This is the most common way to handle errors in those cases and most elegant way in my opinion. Handle error inside error scope:

export const getEmployees = async (companyId) => {
    try {
        const employees = await Employees.find({
            companyId
        });
        // You can add more logic here before return the data.
        return {
            employees
        };
    } catch (error) {
        console.error(error);
    }
};

Assign a default value to the variable in the catch block:

export const getEmployees = async (companyId) => {
    let employees;

    try {
        employees = await Employees.find({
            companyId
        });
        // You can add more logic here before return the data.
        employees = employees;
    } catch (error) {
        console.error(error);
    }

    if (employees) { // We received the data successfully.
        console.log(employees)
        // Business logic goes here.
    }

    return employees;
};

Inspect error instance and act accordingly:

export const getEmployees = async (companyId) => {
    try {
        const employees = await Employees.find({
            companyId
        });
        // You can add more logic here before return the data.
        return {
            employees
        };
    } catch (error) {
        if (error instanceof ConnectionError) {
            console.error(error);
        } else {
            throw error;
        }
    }
};

Some more explanations about async await and more useful methods that you can find in those answers. How run async / await in parallel in Javascript

Upvotes: 4

Related Questions