41

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 :)

ketysek
  • 1,159
  • 1
  • 16
  • 46
  • 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. – Prusse Oct 20 '15 at 14:39
  • `'use strict';` is first line of my controller file. But how can I delete the password property? – ketysek Oct 20 '15 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 `undefined`will not be enough (sorry, no experience with mean-stack)? As far as json encoding goes there should be no difference in result. – Prusse Oct 20 '15 at 14:50
  • nope, setting the property to undefined doesn't work ... hasOwnProperty returned false, as you expected – ketysek Oct 20 '15 at 14:56

9 Answers9

62

Just do:

user.password = undefined;

instead of:

delete user.password;

and the password property will not appear at the output.

LEMUEL ADANE
  • 8,336
  • 16
  • 58
  • 72
  • 3
    this will definitely lead to unexpected results in many cases – E.A.T Sep 04 '19 at 13:46
  • 7
    @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. – LEMUEL ADANE Sep 07 '19 at 21:34
  • 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 Sep 09 '19 at 00:38
  • 3
    @E.A.T, so I guess, he needs to user.save() first then user.password = undefined then res.json(user). – LEMUEL ADANE Sep 09 '19 at 18:01
  • 2
    but why delete user.password is not wroking? – Sunil Garg Jul 18 '22 at 08:47
25

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

Virendra Yadav
  • 652
  • 8
  • 18
15

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; 

Majed A
  • 151
  • 1
  • 3
10

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'}
    ] 
 */ 
Sandeep Amarnath
  • 5,463
  • 3
  • 33
  • 43
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.
Bw. Kizito
  • 68
  • 7
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

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})
Regular Jo
  • 5,190
  • 3
  • 25
  • 47
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)
Kamal Zaitar
  • 101
  • 1
  • 3
0

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.