24

I have a JS object like this:

var tenants = {
    'first': {
        'name': 'first',
        'expired': 1
    },
    'second': {
        'name': 'second'
    }
}

And I'd like to delete the 'expired' property of tenant 'first', should I just do this?

delete tenants['first']['expired'];

Note: this question is more specific than the question: How do I remove a property from a JavaScript object?, in that my question focuses on the 'nested' part.

Community
  • 1
  • 1
lgc_ustc
  • 1,324
  • 2
  • 15
  • 31
  • 1
    Short answer: Yes. More info: http://stackoverflow.com/questions/208105/how-to-remove-a-property-from-a-javascript-object – jeff carey Nov 21 '16 at 03:22

6 Answers6

25

Yes. That would work.

delete tenants['first']['expired']; or delete tenants.first.expired;.

If you are deleting it only because you wanted to exclude it from JSON.stringify(), you can also just set it to undefined, like tenants['first']['expired'] = undefined;

Meligy
  • 34,211
  • 11
  • 83
  • 106
14

If the property you want to delete is stored in a string, you can use this function

function deletePropertyPath (obj, path) {

  if (!obj || !path) {
    return;
  }

  if (typeof path === 'string') {
    path = path.split('.');
  }

  for (var i = 0; i < path.length - 1; i++) {

    obj = obj[path[i]];

    if (typeof obj === 'undefined') {
      return;
    }
  }

  delete obj[path.pop()];
};

Example Usage

var tenants = {
    'first': {
        'name': 'first',
        'expired': 1
    },
    'second': {
        'name': 'second'
    }
}

var property = 'first.expired';    
deletePropertyPath(tenants, property);
Dónal
  • 181,534
  • 169
  • 555
  • 808
11

If your app is using lodash, then _.unset is a safe way for deleting nested properties. You can specify nested keys without worrying about their existence.

let games = { 'hitman': [{ 'agent': { 'id': 47 } }] };
_.unset(games, 'hitman[0].agent.id');
_.unset(games, 'hitman[0].muffin.cupcake'); // won't break

further reading: https://lodash.com/docs/4.17.15#unset

ArielGro
  • 785
  • 1
  • 13
  • 23
ksankar
  • 405
  • 7
  • 13
3

I came up with this:

const deleteByPath = (object, path) => {
  let currentObject = object
  const parts = path.split(".")
  const last = parts.pop()
  for (const part of parts) {
    currentObject = currentObject[part]
    if (!currentObject) {
      return
    }
  }
  delete currentObject[last]
}

Usage:

deleteByPath({ "a" : { "b" : true }},"a.b")
Philipp Kief
  • 7,072
  • 4
  • 34
  • 42
Richard
  • 14,029
  • 9
  • 53
  • 83
2

If you have the path of the key separated by ., say first.expired in your case, you can do deleteKey(tenants, 'first.expired'):

const deleteKey = (obj, path) => {
    const _obj = JSON.parse(JSON.stringify(obj));
    const keys = path.split('.');

    keys.reduce((acc, key, index) => {
        if (index === keys.length - 1) {
            delete acc[key];
            return true;
        }
        return acc[key];
    }, _obj);

    return _obj;
}

let tenants = {
    'first': {
        'name': 'first',
        'expired': 1
    },
    'second': {
        'name': 'second'
    }
};

const PATH_TO_DELETE = 'first.expired';

tenants = deleteKey(tenants, PATH_TO_DELETE);
console.log('DELETE SUCCESSFUL:', tenants);
1

If you want to delete a property with a particular name in an arbitrarily deep object, I would recommend that you use a battle-tested library. You can use DeepDash, an extension to Lodash.

  // Recursively remove any "expired" properties
  _.eachDeep(e, (child, prop, parent, ctx):boolean => {
    if (prop === 'expired') {
      delete parent[prop];
      return false; // per docs, this means do not recurse into this child
    }
    return true;
  });

And if you would rather have a new copy (rather than mutating the existing object), DeepDash also has an omitDeep function you can use that will return the new object.

Robert
  • 760
  • 9
  • 14