1

I'm trying to using the Mongoose Promises to have a cleaner code (see nested functions). Specifically, I'm trying to build something like this:

Model.findOne({_id: req.params.id, client: req.credentials.clientId}).exec()
   .then(function(resource){
      if (!resource) {
        throw new restify.ResourceNotFoundError();
      }
      return resource;
    })
    .then(function(resource) {
      resource.name = req.body.name;
      return resource.save; <-- not correct!
    })
    .then(null, function(err) {
       //handle errors here
    });

So, in one of the promises I would need to save my model. As of the latest stable release, Model.save() does not return a promise (bug is here).

To use the classical save method, I could use this:

   //..before as above
   .then(function(resource) {
      resource.name = req.body.name;
      resource.save(function(err) {
        if (err)
            throw new Error();
        //how do I return OK to the parent promise?
      });
    })

But as also commented in the code, how do I return to the holding promise the return value of the save callback (which runs async)?

Is there a better way?

(btw, findOneAndUpdate is a no-go solution for my case)

Community
  • 1
  • 1
Roberto
  • 2,206
  • 4
  • 24
  • 31

1 Answers1

1

One way of doing it would be to wrap the .save code in your own method which returns a promise. You'll need a promise library, like RSVP or Q. I'll write it in RSVP, but you should get the idea.

var save = function(resource) {
  return new RSVP.Promise(function(resolve, reject) {
    resource.save(function(err, resource) {
      if (err) return reject(err);
      resolve(resource);
    });
  });
}

Then in your calling code:

// ...

.then(function(resource) {
  resource.name = req.body.name;
  return save(resource);
})
.then(function(resource) {
  // Whatever
})
.catch(function(err) {
 // handle errors here
});

The other way of doing it would be to nodeify the save method, but I'd do it they way I've detailed above.

Johnny Hall
  • 545
  • 4
  • 12
  • 1
    I suggest Bluebird over RSVP as it's faster and a lot more debuggable. Bluebird makes it `var save = Promise.promisify(someResource.prototype.save)` – Benjamin Gruenbaum May 07 '14 at 10:53
  • @BenjaminGruenbaum while RSVP it works as JohnnyHall wrote, it seems that Bluebird implementation of promises is not compatible with the ones of Mongoose (it always takes the promise to run the catch function)...still it seems cleaner and it would be nice to use... any clues? – Roberto May 07 '14 at 12:43
  • Yes, the problem was about the scope of the function. Finally, I opted to ```return Promise.promisify(resource.save,resource)();``` – Roberto May 07 '14 at 15:12