Michael Pratt
Michael Pratt

Reputation: 3496

Node.js deferred promisify + mongoose

Has anyone worked with the nodejs modules 'deferred' and 'mongoose'? I'm trying to get the deferred.promisify method to work on mongoose models' functions so I can chain them easily, but running into some troubles. Specifically, I'd like to promisify the find and findById functions so I can chain finding one document referenced by another document by ObjectID.

Here's what I've got: https://gist.github.com/3321827

However, this seems less than ideal since the getAppPermissions and getApplication functions seem to be little more than wrappers for the find and findById methods of the mongoose model.

I tried just passing the functions to promisify, but I get an error about Object #<Object> has no method '_applyNamedScope' which appears to be caused because this is no longer bound to the correct object. Perhaps I need to use underscore.bind? Has anyone had any success in this area, or should I just stick with what's working now?

Upvotes: 0

Views: 2281

Answers (2)

Michael Pratt
Michael Pratt

Reputation: 3496

Mariusz's answer was pretty close. Here's what ended up working for me in this particular case, hopefully others can learn from this:

// I put this in my model file so I didn't have to worry about repeating it
var userProto = mongoose.model('User');

userProto.pFind = deferred.promisify(userProto.find);
userProto.pFindOne = deferred.promisify(userProto.findOne);

Upvotes: 2

Mariusz Nowak
Mariusz Nowak

Reputation: 32848

You probably didn't pass context to methods properly, right way to do this is to provide promisified versions of methods directly on Mongoose prototype:

// I assume that methods you're using are set on mongoose.Model,
// but be sure to check, maybe, they're using some other prototype (!)
var promisify = require('deferred').promisify;
var modelProto = mongoose.Model.prototype;
modelProto.pFind = promisify(modelProto.find);
modelProto.pFindById = promisify(modelProto.findById);

// After that you may use promisified methods directly:
app.get('/apps', requireLogin, function (req, res) {    
  AppPermissions.pFind({ user: req.user.id, valid: true })
    .map(function (permission) {
      return ApplicationRecord.pFindById(permission.application)(
        function (application) {
          application.permission = permisson;
          return application;
        }
      );
    }).end(function (applications) {
      res.render('applist', { applications: applications });
    }, null);
});

You can also refrain from polluting the prototype, and use methods indirectly:

var promisify = require('deferred').promisify;
var modelProto = mongoose.Model.prototype;
var pFind = promisify(modelProto.find);
var pFindById = promisify(modelProto.findById);

app.get('/apps', requireLogin, function (req, res) {    
  pFind.call(AppPermissions, { user: req.user.id, valid: true })
    .map(function (permission) {
      return pFindById.call(ApplicationRecord, permission.application)(
        function (application) {
          application.permission = permisson;
          return application;
        }
      );
    }).end(function (applications) {
      res.render('applist', { applications: applications });
    }, null);
});

Upvotes: 2

Related Questions