Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inside Schema method scopes "this" is empty {} in Mongoose 4.4.12

The object "this" is "{}" when logged to the console inside a Schema method. This occurred one day ago and I've been reading up tutorials and other stack overflow questions, but to no luck have I found a solution as to why.

Here is my model:

var mongoose    = require("mongoose");
var Schema      = mongoose.Schema;
var constants   = require("../config/constants");
var bcrypt      = require("bcrypt-nodejs");


var UserSchema = new Schema({
    name: String,
    email: String,
    password: String,
    authorization:
    {
        type: Number,
        default: constants.authorization.default
    }
});

UserSchema.pre("save", (next) => {
    var user = this;

    /**
     * Only hash the password when it's been modified or if new.
     */

    // #####################################################
    // ERROR
    // if (!query.isModified("password"))
    //            ^
    // TypeError: query.isModified is not a function
    //
    // user and this == {}
    // ####################################################
    if (!user.isModified("password"))
    {
        return next();
    }

    /**
     * hash password
     */
    bcrypt.hash(user.password, null, null, (err, hash) => {
        if (err)
        {
            return next(err);
        }

        user.password = hash;
        return next();
    });
});

// #####################################################
// ERROR
// user.verifyPassword(req.body.password, match => {
//     ^
// TypeError: user.verifyPassword is not a function
//
// this == {}
// ####################################################
UserSchema.methods.verifyPassword = (reqPassword, callback) => {
    bcrypt.compare(reqPassword, this.password, (err, match) => {
        var e = null;
        var m = match;

        if (err)
        {
            e = err;
            m = false;
        }

        return callback(e, m);
    });
};



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

And this is how I use it (I've marked where the break happens):

//includes express, mongoose, User, constants. this part is ok.

/**
 * Authenticates a user post request
 *
 * @request email string
 * @request password string
 *
 */
router.post("/", (req, res) => {
    /**
     * Retrieve the user
     */
    User.find(
    {
        email: req.body.email
    },
    (err, user) =>
    {
        /**
         * An error occurred
         */
        if (err)
        {
            return res.json({
                success:    false,
                message:    "An mongodb error occurred.",
                error:      err
            });
        }

        /**
         * Check for problems with the email or password.
         */
        if (!user)
        {
            return res.json({
                success:    false,
                message:    "Email or password was incorrect."
            });
        }

        // ##########################################################
        // ERROR
        // user.verifyPassword(req.body.password, match => {
        //     ^
        // TypeError: user.verifyPassword is not a function
        // ##########################################################
        user.verifyPassword(req.body.password, match => {
            if (!match)
            {
                return res.json({
                    success:    false,
                    message:    "Email or password was incorrect."
                });
            }

            /**
             * User authenticated!
             */
            req.session.user = user;
            res.json({
                success: true,
                message: "Successfully authenticated."
            });
        });

    });
});

router.get("/", (req, res, next) => {
    var admin = new User({
        name: "admin",
        email: "[email protected]",
        password: "admin",
        authorization: constants.authorization.admin
    });

    // ########################################################
    // ERROR
    // if (!user.isModified("password"))
    //            ^
    // TypeError: user.isModified is not a function
    // #######################################################
    admin.save(function(err) {
        if (err)
        {
            console.log(err);
        }

        console.log('User saved successfully');
        res.json({ success: true });
    });
});

Does anyone know the problem of this?

like image 623
andersfylling Avatar asked Apr 22 '16 13:04

andersfylling


People also ask

Can you define methods in a Mongoose schema?

Each Schema can define instance and static methods for its model.

What is schema type in Mongoose?

Mongoose Schematype is a configuration for the Mongoose model. Before creating a model, we always need to create a Schema. The SchemaType specifies what type of object is required at the given path. If the object doesn't match, it throws an error.

What is schema path Mongoose?

You can think of a Mongoose schema as the configuration object for a Mongoose model. A SchemaType is then a configuration object for an individual property. A SchemaType says what type a given path should have, whether it has any getters/setters, and what values are valid for that path.

What does the schema in Mongoose define in MongoDB?

With Mongoose, you would define a Schema object in your application code that maps to a collection in your MongoDB database. The Schema object defines the structure of the documents in your collection. Then, you need to create a Model object out of the schema. The model is used to interact with the collection.


1 Answers

The problem might be related to the fact that you're using ES6 arrow syntax instead of a plain function as the callback. ES6 arrow functions change the semantics of the this keyword, which might affect how mongoose handles the callback internally.

Try

UserSchema.pre("save", function(next) {
    // ...
});

instead of

UserSchema.pre("save", (next) => {
    // ...
});
like image 119
Toni Sučić Avatar answered Sep 29 '22 21:09

Toni Sučić