Why does mongoose model's hasOwnProperty retur

2019-01-27 13:43发布

问题:

I have this code :

user.findOne( { 'email' : email }, function( err, User )
            {
                if ( err )
                {
                    return done(err);
                }
                if ( !User )
                {
                    return done(null, false, { error : "User not found"});
                }
                if ( !User.hasOwnProperty('local') || !User.local.hasOwnProperty('password') )
                {
                    console.log("here: " + User.hasOwnProperty('local')); // displays here: false
                }
                if ( !User.validPass(password) )
                {
                    return done(null, false, { error : "Incorrect Password"});
                }
                return done(null, User);
            });

Since the app supports other kinds of authentication, I have a user model that has nested object called local which looks like

local : { password : "USERS_PASSWORD" }

So during login I want to check whether the user has provided a password but I encountered this interesting problem. My test object looks like this:

{ _id: 5569ac206afebed8d2d9e11e,
email: 'test@example.com',
phno: '1234567890',
gender: 'female',
dob: Wed May 20 2015 05:30:00 GMT+0530 (IST),
name: 'Test Account',
__v: 0,
local: { password: '$2a$07$gytktl7BsmhM8mkuh6JVc3Bs/my7Jz9D0KBcDuKh01S' } } 

but console.log("here: " + User.hasOwnProperty('local')); prints here: false

Where did I go wrong?

回答1:

It's because the document object you get back from mongoose doesn't access the properties directly. It uses the prototype chain hence hasOwnProperty returning false (I am simplifying this greatly).

You can do one of two things: use toObject() to convert it to a plain object and then your checks will work as is:

var userPOJO = User.toObject();
if ( !(userPOJO.hasOwnProperty('local') && userPOJO.local.hasOwnProperty('password')) ) {...}

OR you can just check for values directly:

if ( !(User.local && User.local.password) ) {...}

Since neither properties can have a falsy value it should work for testing if they are populated.

EDIT: Another check I forgot to mention is to use Mongoose's built in get method:

if (!User.get('local.password')) {...}


回答2:

If you only need the data and not the other Mongoose magic such as .save(), .remove() etc then the most simple way would be to use .lean():

user.findOne( { 'email' : email }, function( err, User ).lean()
            {
                if ( err )
                {
                    return done(err);
                }
                if ( !User )
                {
                    return done(null, false, { error : "User not found"});
                }
                if ( !User.hasOwnProperty('local') || !User.local.hasOwnProperty('password') )
                {
                    console.log("here: " + User.hasOwnProperty('local')); // Should now be "here: true"
                }
                if ( !User.validPass(password) )
                {
                    return done(null, false, { error : "Incorrect Password"});
                }
                return done(null, User);
            });


回答3:

You can also detach the returned JSON from MongoDB Schema - JSONuser = JSON.parse(JSON.stringify(User)) - and then use JSONuser freely getting, changing or adding, any of its properties.