简体   繁体   中英

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?

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);
});

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM