Search code examples
node.jsmongoosemongoose-populate

Why can't I access a mongoose schema's method?


I have this Mongoose schema in a Nodejs application:

const mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    sodium = require('sodium').api;

const UserSchema = new Schema({
    username: {
        type: String,
        required: true,
        index: { unique: true }
    },
    salt: {
        type: String,
        required: false
    },
    password: {
        type: String,
        required: true
    }
});

UserSchema.methods.comparePassword = function(candidatePassword, targetUser) {
    let saltedCandidate = candidatePassword + targetUser.salt;
    if (sodium.crypto_pwhash_str_verify(saltedCandidate, targetUser.password)) {
        return true;
    };
    return false;
};

module.exports = mongoose.model('User', UserSchema);

And I created this routes file.

const _ = require('lodash');
const User = require('../models/user.js'); // yes, this is the correct location

module.exports = function(app) {
    app.post('/user/isvalid', function(req, res) {
        User.find({ username: req.body.username }, function(err, user) {
            if (err) {
                res.json({ info: 'that user name or password is invalid. Maybe both.' });
            };
            if (user) {
                if (User.comparePassword(req.body.password, user)) {
                    // user login
                    res.json({ info: 'login successful' });
                };
                // login fail
                res.json({ info: 'that user name or password is invalid Maybe both.' });
            } else {
                res.json({ info: 'that user name or password is invalid. Maybe both.' });
            };
        });
    });
};

I then use Postman to make a call to 127.0.0.1:3001/user/isvalid with an appropriate Body content. The terminal says tell me TypeError: User.comparePassword is not a function and crashes the app.

Since the if (user) bit passes, that indicates to me that I have properly retrieved a document from Mongo and have an instance of the User schema. Why is the method not valid?

eta: the module export I failed to copy/paste originally


Solution

  • This creates instance method:

    UserSchema.methods.comparePassword = function(candidatePassword, targetUser) {
        // ...
    };
    

    If you want a static method use this:

    UserSchema.statics.comparePassword = function(candidatePassword, targetUser) {
        // ...
    };
    

    Static methods are when you want to call it as User.comparePassword().

    Instance methods are when you want to call it as someUser.comparePassword() (which in this case would make a lot of sense so that you wouldn't have to pass the user instance explicitly).

    See the documentation: