44

I'm running some project on MEAN.js and I've got a following problem. I want to make some user's profile calculation and the save it to database. But there's a problem with method in users model:

UserSchema.pre('save', function(next) {
    if (this.password && this.password.length > 6) {
        this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
        this.password = this.hashPassword(this.password);
    }
    next();
});

If I will send a password with my changes, it will change credentials, so user is unable to login next time. I want to delete password from user object before save, but I'm not able to do it (let's look at the comments in my code below):

exports.signin = function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
        if (err || !user) {
            res.status(400).send(info);
        } else {
            /* Some calculations and user's object changes */
            req.login(user, function(err) {
                if(err) {
                    res.status(400).send(err);
                } else {
                    console.log(delete user.password); // returns true
                    console.log(user.password); // still returns password :(
                    //user.save();
                    //res.json(user);
                }
            });
        }
    })(req, res, next);
};

What's wrong? Why the delete method returns true, but nothing happens? Thanks for your help :)

4
  • 1
    Not strict mode delete will return true even when the property can't be deleted. Also delete will return true and have no effect when the property is obtained through the prototype chain. Commented Oct 20, 2015 at 14:39
  • 'use strict'; is first line of my controller file. But how can I delete the password property? Commented Oct 20, 2015 at 14:43
  • It seem unlikely to be the case but did you check if the password property is actually a property of the user object and doesn't come from someone on the prototype chain (hasOwnProperty)? Setting it to undefinedwill not be enough (sorry, no experience with mean-stack)? As far as json encoding goes there should be no difference in result. Commented Oct 20, 2015 at 14:50
  • nope, setting the property to undefined doesn't work ... hasOwnProperty returned false, as you expected Commented Oct 20, 2015 at 14:56

10 Answers 10

65

Just do:

user.password = undefined;

instead of:

delete user.password;

and the password property will not appear at the output.

Sign up to request clarification or add additional context in comments.

7 Comments

this will definitely lead to unexpected results in many cases
@E.A.T, the guy does not really need to delete the password property. From what he described above, he just wanted to exclude the value of the password in the output JSON, and just by making the password property undefined you can address that. Try it.
No @lemueladane, he wants to avoid overwriting the password when calling user.save(), which may happen still if it's set as undefined or null. We dont have enough info about method or any presave hooks.
@E.A.T, so I guess, he needs to user.save() first then user.password = undefined then res.json(user).
but why delete user.password is not wroking?
user maybe is not pojo. delete only removes pojo properties.
take a look at the next answer.
28

there are certain rules for delete operator in javascript

  1. if the property is an own non-configurable property in "strict mode" than it will return false.

for example

x = 42;         // creates the property x on the global object
var y = 43;     // creates the property y on the global object, and marks it as non-configurable

// x is a property of the global object and can be deleted
delete x;       // returns true

// y is not configurable, so it cannot be deleted                
delete y;       // returns false 
  1. If the object inherits a property from a prototype, and doesn't have the property itself, the property can't be deleted by referencing the object. You can, however, delete it directly on the prototype.

for example

function Foo(){}
Foo.prototype.bar = 42;
var foo = new Foo();

// returns true, but with no effect, 
// since bar is an inherited property
delete foo.bar;           

// logs 42, property still inherited
console.log(foo.bar);

so, please cross check these point and for more information your can read this Link

Comments

17

Had a similar problem. This worked for me:

// create a new copy  
let newUser= ({...user}._doc); 

// delete the copy and use newUser that thereafter. 
delete newUser.password; 

Comments

13

Working with MONGOOSE?

If you're facing this issue when working with Mongoose (Mongo DB's upper layer) then you can use lean property on find method

Examples

Without lean (The keys won't be deleted)

const users = await User.find({ role: 'user' }) // no lean method
   users.forEach((user) => {
   delete user.password  // doesn't delete the password
})

console.log(users) 

/* [
    {name:'John', password:'123'}, 
    {name:'Susan', password:'456'}
   ] 
*/ 

With lean (The keys get deleted)

const users = await User.find({ role: 'user' }).lean() 
   users.forEach((user) => {
   delete user.password   // deletes the password
})

console.log(users) 

/* [
    {name:'John'}, 
    {name:'Susan'}
   ] 
*/ 

Reason why lean works

Documents returned from queries with the lean option enabled are plain javascript objects, not Mongoose Documents. They have no save method, getters/setters, virtuals, or other Mongoose features.

Documents are kind of read-only, so delete doesn't work on them

Reference - https://stackoverflow.com/a/48137096/10824697 https://mongoosejs.com/docs/api.html#query_Query-lean

Method 2 without lean

If you want to use the mongoose provided method to remove some property while you are querying, you can remove with select method,

const users = await User.find({ role: 'user' }).select('-password')

console.log(users)
 /* [
      {name:'John'}, 
      {name:'Susan'}
    ] 
 */ 

4 Comments

At first example you forgot one dot after password
Thanks @Kamuran Sönecek. Updated!
Thank you! This might also help some: const _doc = doc.toObject(); delete _doc.prop1;. (Using delete directly won't work on Mongoose document objects because they're configured to be non-editable. toObject() turns them into plain objects first. Then delete will work.)
4

The answer above from Majed A is the simplest solution that works for single objects properties, we can even make it for more easier by removing the ...user spreader. just delete the property from your object._doc sub-object. in your example it would have been:

user.save()
delete user._doc.password
res.status(201).json(user) // The password will not be shown in JSON but it has been saved.

Comments

1

The most likely, property which you want to delete has not owned the property for this object. In this case, the result of the operation will show true but nothing will be deleted.

Comments

0

Had a similar issue. The delete operator "was not working" when trying to delete a property from an object in a specific case. Fixed it using Lodash unset:

_.unset(user, "password");

https://lodash.com/docs/4.17.11#unset

Otherwise the delete operator does work. Just in case, delete operator docs here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete

Comments

0

If password was defined with defineProperty, then configurable defaults to false if not set. In that case, then the property can't be deleted.

For me, node js still tells me the property was deleted (console.log(delete obj.prop)), but it wasn't deleting.

function test(settings) {
  settings = {...{c: false, w:false}, ...settings}
  let obj = {}
  Object.defineProperty(obj, "prop", {
    configurable: settings.c,
    enumerable: settings.e ?? true,
    writable: settings.w,
    value: "foo"
  });
  console.log(
    JSON.stringify(settings), 
    '\nset value to 1', (function() {obj.prop = 1})() || "", 
    '\nappended bar:', (function() {obj.prop += "bar"})() || "", 
    '\nobj:', JSON.stringify(obj),
    '\ndelete:', delete obj['prop'],
    '\nobj:', JSON.stringify(obj))
}
console.log('baseline: unchangeable, undeletable');
test()
console.log('unchangeable, deletable');
test({c: true})
console.log('changeable, undeletable');
test({w: true})
console.log('changeable, deletable');
test({c: true, w: true})

Comments

0

You may use this. It skips the unwanted key instead of deleting, it then returns the object.

Object = remove(Object, keyToRemove)

  let x = {1:1, 2:2}

    console.log('in', x)
    
    function remove(Object, key){

        let outputObject = {}

        for (let inKey in Object){

            if(key == inKey){

                console.log('key', key , 'was deleted')

            }else{

               outputObject[inKey] = Object[inKey]

            }

        }

        return outputObject

    }

 x = remove(x, 1)

    console.log('out', x)

Comments

0

just convert the mongo doc to js object

const data = (await User.create(newUser)).toObject();

then you can delete it

delete (data as any).password;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.