7

I was going through the mongoose docs when I Stumbled upon the line saying

Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. If you need a fully-fledged promise, use the .exec() function.

With this example

var query = Band.findOne({name: "Guns N' Roses"});
assert.ok(!(query instanceof Promise));

// A query is not a fully-fledged promise, but it does have a `.then()`.
query.then(function (doc) {
  // use doc
});

// `.exec()` gives you a fully-fledged promise
var promise = query.exec();
assert.ok(promise instanceof Promise);

promise.then(function (doc) {
  // use doc
});

Now, I didn't get what they meant when they said fully-fledge promise, like for me .then() should be a promoise and then it also allows async and await.

So can someone please explain me what does fully-fledge promise mean?

Reference link: https://mongoosejs.com/docs/promises.html#queries-are-not-promises

Alwaysblue
  • 9,948
  • 38
  • 121
  • 210
  • "*like for me `.then()` should be a promise*" - but what if there is a `then` but it's not a promise? We call that [a **thenable**](https://stackoverflow.com/q/29435262/1048572). – Bergi Nov 25 '18 at 18:26

2 Answers2

10

That means that the values returned by queries are thenables per the definition of the Promises/A+ spec, but not actual Promise instances. That means they may not have all of the features of promises (for instance, catch and finally methods). Actual Promise instances would be "fully-fledged" promises.

The English term "fully-fledged" means "complete" or "fully developed." It comes from ornithology (or at least, terminology related to birds): A chick (a young bird) that has its adult feathers is "fledged;" if it has all its adult feathers completely covering its down undercoat, it's fully-fledged.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

@T.J. Crowder's answer really helped me clarify a lot of things (I came across this post coz I was confused too), and I just wanted to supplement it a little here :)

Traditionally, the then() method returns a Promise. It takes up to two arguments: callback functions for the success (onFulfilled) and failure (onRejected) cases of the Promise. Thenables, however, does not work this way. We won't be able to pass in two callback functions like how we did with a "fully-fledged promise". To illustrate this with some code:

UserModel.find().exec((err, users) => {
  if (err) return res.status(400).send(err);
  res.status(200).json({
    success: true,
    users,
  });
});

This works fine because the two callback functions we passed in for the success and failure cases are called err (failure case) and the success/result case is called users.  Note that all callbacks in Mongoose use the pattern: callback(error, result) - this is different from the order of the callback functions specified in the MDN web docs. Now, if we run the same piece of code but replace exec() with then() like so:

UserModel.find().then((err, users) => {
  if (err) return res.status(400).send(err);
  res.status(200).json({
    success: true,
    users,
  });
});

This returns a 400 Bad Request Status.

This is because Mongoose queries are not "fully-fledged promises" and so we cannot chain a .then() behind a query and then expect it to act like a real promise.

However, from what I've tried, you can actually still use .catch() for error handling like so:

// {_id:1} is included to make this fail
UserModel.find({ _id: 1 })
  .then((users) => {
    res.status(200).json({
      success: true,
      users,
    });
  })
  .catch((err) => {
    res.status(400).send(err);
  });
Reine_Ran_
  • 662
  • 7
  • 25