How do you call Mongoose functions when it has a callback?

In Mongoose, to avoid “callback hell” I wrote all the operations that interact with the database in separate functions to have it modular. All these functions have a ‘done’ callback parameter as the last argument. But now I’m super confused…

  1. How do you call these functions given the ‘done’ parameter?
  2. How do you implement one of the find functions in an if statement?

For example, the function written below… how do you call it by itself, and how can you integrate this into an if function to see if personName is in the database or not?

var findPeopleByName = function(personName, done) {
  Person.find({name: personName}, function (err, personFound) {
    if (err) return console.log(err);
    done(null, personFound);
  });
};

I don’t fully understand what you mean, however this is what you are talking about I believe.

// Define function (takes name as a param). we can use async await.
const personInDB = (name) => {
    const person = Person.find({name: name}); 
   
     // If person is in Database
      if (person) return true;
      else {
          return false;
   }

}
  1. You can call these functions by supplying a callback as an argument to the “done” parameter:
findPeopleByName(personName, (null, personFound) => {
  // Do something with personFound
});
  1. You can call the above function inside an if statement as any other function:
if (personNameIsInDatabase) {
  findPeopleByName(personName, (null, personFound) => {
    // Do something with personFound
  });
}

But I think the current best practices are to use the async/await syntax (which all recent versions of Node.js support):

const findPeopleByNameAndDoSomething = async personName => {
  try {
    const personFound = await Person.find({ name: personName });
    // Do something with personFound
  } catch (err) {
    console.log(err);
  }
};

https://mongoosejs.com/docs/promises.html

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await

1 Like

Thanks! So most people don’t use the last parameter as a callback anymore in terms of current best practice right?

I think I just get confused with the last callback parameter in every function… so if I want to use the result in an If statement, I’d have to define it first and put the result in the if statement right…? I just get confused when trying to do it all at once and trying to handle the error in the if evaluator.

I think the code below should work…?

let personA = findPeopleByName("John", function(err, data) {
  if (err) return (err);
  return data;
}
if (personA === "John") {
// do something
}

But I think I got confused with the below… would be open to your thoughts if it’s correct - albeit convoluted.

if (findPeopleByName("John", function(err, data) {
  if (err) return err);
  return data;
} === "John") {
// do something
}

JavaScript promises were introduced to alleviate the problem of callback hell, and the newer async/await syntax was introduced to improve upon promises and eliminate the heavy nesting in callbacks and sometimes in promises.

Your code returns data from inside a callback, so you can’t just assign the data to a variable as the return value of the outer function.

If you want to check the data and use them, you need to do so from inside the callback.

And mongoose model find method returns an array of objects, not a string.

So I would do something like this if I was using the callback syntax:

findPeopleByName('John', (err, data) => {
  if (err) {
    return console.log(err);
  }

  if (data.length === 0) {
    return console.log('No person with the name John was found.');
  }

  const personA = data[0];
  if (personA.name === 'John') {
    // Do something with personA
  }
});

And if I was using the async/await syntax, I’d do something like this:

(async () => {
  try {
    const peopleFound = await Person.find({ name: 'John' });
    if (peopleFound.length === 0) {
      return console.log('No person with the name John was found.');
    }

    const personA = peopleFound[0];
    if (personA.name === 'John') {
      // Do something with personA
    }
  } catch (err) {
    console.log(err);
  }
})();

But now that I think about it, checking for name John is redundant because Person.find({ name: ‘John’ }) would only return Johns or an empty array.

But if you want to check for some other property such as personA.age > 25, I would do so as in the conditional as in the above code samples.

Here are some code examples of using mongoose with callbacks vs. async/await:

https://www.codepedia.org/ama/cleaner-code-in-nodejs-with-async-await-mongoose-calls-example

1 Like