Adding static methods to mongoose models using plugins

519 views
Skip to first unread message

John Farrow

unread,
Oct 26, 2015, 4:37:30 AM10/26/15
to Mongoose Node.JS ODM
I want to be able to add static methods to models dynamically. I want to add methods to findBy{PathName}

    function findByCurry(key) {
        return function(value, cb) {
            var model = this.model(this.constructor.modelName);
            return model.find({
                key: value
            }, cb);
        }
    }
    
    
    module.exports = function(schema) {
        var keys = Object.keys(schema.paths).filter((key) => {return !!key[0].match(/[a-zA-Z]/)});
            titleKeys = keys.map((key) => {return key.replace(/\w/, function(txt) {return txt.charAt(0).toUpperCase()});});
        
        keys.forEach((key, i) => {
            schema.statics['findBy' + titleKeys[i]] = findByCurry(key);
        });
    }

Currently, the method is not being attached to the model instance. I suspect it's something to do with the forEach, but I can't be sure because nothing seems to get console logged at any point within the plugin. 

Valeri Karpov

unread,
Oct 26, 2015, 8:47:58 PM10/26/15
to Mongoose Node.JS ODM
Hmm that's weird, are you actually calling the plugin? If nothing gets printed even if you put a console.log at the top of the function call, that might be the case. Can you show me how you're using this plugin?

John Farrow

unread,
Oct 27, 2015, 3:16:46 AM10/27/15
to mongoo...@googlegroups.com
I am requiring within my model:


var venueSchema = new Schema({
      title: {type: String, required: true, validate: validator.basicName()},
    });


venueSchema.plugin(require('../classes/MagicMethods'));


then in my routes:

var venue = Venue.findByTitle(req.body.title);

this method is not found.

--
Documentation - http://mongoosejs.com/
Plugins - http://plugins.mongoosejs.com/
Bug Reports - http://github.com/learnboost/mongoose
Production Examples - http://mongoosejs.tumblr.com/
StackOverflow - http://stackoverflow.com/questions/tagged/mongoose
Google Groups - https://groups.google.com/forum/?fromgroups#!forum/mongoose-orm
Twitter - https://twitter.com/mongoosejs
IRC - #mongoosejs
---
You received this message because you are subscribed to a topic in the Google Groups "Mongoose Node.JS ODM" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/mongoose-orm/VB3XsqZF8XY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to mongoose-orm...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Richard Bateman

unread,
Oct 27, 2015, 9:14:42 PM10/27/15
to mongoo...@googlegroups.com
Have you added some logging in your export function to make sure your titleKeys are being generated correctly?

Richard

You received this message because you are subscribed to the Google Groups "Mongoose Node.JS ODM" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mongoose-orm...@googlegroups.com.

John Farrow

unread,
Oct 28, 2015, 5:46:14 AM10/28/15
to mongoo...@googlegroups.com
Okay, so I have the methods being attached:

module.exports = function(schema) {
    function findBy(key) {
        return function(value, model) {
            console.log('find by ' + key + ': ' + value);
            return this.find({
                key: value
            }, cb);
        }
    }

    var keys = Object.keys(schema.paths).filter((key) => {return !!key[0].match(/[a-zA-Z]/)});
        titleKeys = keys.map((key) => {return key.replace(/\w/, function(txt) {return txt.charAt(0).toUpperCase()});});
    keys.forEach((key, i) => {
        schema.statics['findBy' + titleKeys[i]] = findBy(key);
    });
}


I have a scheme like so: 
var uuid = require('node-uuid');

var venueSchema = new Schema({
      slug: { type: String, unique: true, default: uuid.v1 }
 });
venueSchema.plugin(require('../classes/MagicMethods'));

and a model:

Venue = mongoose.model('Venue', venueSchema);

now my problem is that 

Venue.findBySlug(slug, (err, venus) = {
  res.json(venues);
});

returns an empty array, but using the same slug:

Venue.find({slug: slug}, (err, venus) = {
  res.json(venues);
});

returns my expected results.

I have established that Venue is equal to this from the context of the dynamic find method, so to my mind these queries should be identical, but they are not.


John Farrow
Senior Developer |  Aerian

 john....@aerian.com   |  www.aerian.com  |  +44 (0) 345 408 6009   |  +44 (0) 7800 500 608

John Farrow

unread,
Oct 28, 2015, 6:06:09 AM10/28/15
to mongoo...@googlegroups.com
BOOM! 

The problem was that keys can be expressed in an object without quotes, so my query was looking up "key" rather than "slug"

fixed here:

 function findBy(key) {
        return function(value, cb) {
            var query = {};
            query[key] = value;
            console.log(query);
            return this.find(query, cb);
        }
    }

that would have been easy to spot if I knew how to extract a query from a Query object. Must be a way...

John Farrow

unread,
Oct 28, 2015, 6:40:03 AM10/28/15
to mongoo...@googlegroups.com
Thanks for your help.

v0.0.1 is in the wild

Reply all
Reply to author
Forward
0 new messages