Reputation: 3496
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
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
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