Reputation: 5153
I'm in the case of a function being able to search by different fields depending on the situation.
It returns the same dataset, it just searches by different fields: either userId or tagId. Therefore, in my code I have something like this:
var findByMethod;
if (searchBy === 'userId') {
findByMethod = UserArticleModel.findByUser;
}
else {
findByMethod = UserArticleModel.findByTag;
}
findByMethod(idToSearch, function (err, articles) {…});
findByUser
and findByTag
are static methods defined in the UserArticleModel.js
UserArticleModel.js
var mongoose = require('mongoose');
var userArticleSchema = new mongoose.Schema({
…
}
});
userArticleSchema.statics.findByUser = function (userId, callback) {
this.find({userId: userId}, function () {…});
};
userArticleSchema.statics.findByTag = function (tagId, callback) {…};
module.exports = mongoose.model('UserArticle', userArticleSchema);
Back in my controller, when I do:
UserArticleModel.findByTag(idToSearch, function (err, articles) {…});
All is well and things go right. But when I dynamically call the method via my variable:
findByMethod(idToSearch, function (err, articles) {…});
Things go wrong as node returns an error:
DOMAINE ERROR CAUGHT: TypeError: Object #<Object> has no method 'find'
I suspect this
not to be be bound to the correct scope but I don't really understand why as findByMethod === UserArticleModel.findByUser // true
Upvotes: 1
Views: 500
Reputation: 50406
I think you are making this more involved that it need be. Though it is an easy trap to fall into by "too literally" following documented API examples and thinking essentially "this is how I need to hardcode this, because the docs say this is how you do it".
JavaScript objects are, well "Objects", and therefore just assigning "named" static methods which are really only object properties is just a basic process of "looping" the defined "schema paths" from that already defined "Object" and setting up the properties for the "findByFieldName" methods you want.
It's just "assigning named properties" and nothing more obscure or complex or even as "terse" than that.
If that "sounds like a mouthful" then the actual process of iterating object properties and "setting other properties" related to that within an overall object structure is not really as hard as you might think.
As a brief example:
var async = require('async'),
pascal = require('to-pascal-case'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
var testSchema = new Schema({
fieldA: String,
fieldB: Number
});
function setStatics(schema) {
Object.keys(schema.paths).filter(function(key) {
return key != '_id';
}).forEach(function(key) {
schema.statics['findBy' + pascal(key)] = function(arg,callback) {
var query = {};
query[key] = arg;
this.findOne(query,callback);
};
});
};
// Set up findByFieldName other than _id
setStatics(testSchema);
var Test = mongoose.model( 'Test', testSchema, "test" );
mongoose.connect('mongodb://localhost/test');
async.series(
[
function(callback) {
Test.remove({},callback);
},
function(callback) {
Test.create([
{ "fieldA": "a", "fieldB": 1 },
{ "fieldA": "b", "fieldB": 2 }
],callback);
},
function(callback) {
Test.findByFieldA("a",function(err,doc) {
console.log(doc);
callback(err);
});
},
function(callback) {
Test.findByFieldB(2,function(err,doc) {
console.log(doc);
callback(err);
});
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
Which proves that they work by "testing them" with the output:
{ _id: 55f2ae1b7d8315f40b1a2b77, fieldA: 'a', fieldB: 1, __v: 0 }
{ _id: 55f2ae1b7d8315f40b1a2b78, fieldA: 'b', fieldB: 2, __v: 0 }
And that is all there is to it.
Of course for fields like "Arrays" you want to get a little more involved, but this is the basic premise as a listing you can try out yourself ( or selves for the community in general ).
I could also note that there are already a few things out there such as Bluebird via it's own .promisifyAll()
call which interacts with objects to set new up "named methods" on the object in a similar way. Or at least it should be similar in principle, as I have not actually looked at that code.
Upvotes: 1