4

I have a complex javascript object containing multiple nested arrays and maps. I would like to delete every field of the object with a given name.

For example:

{
  "myObj":{
    "name":"John",
    "deleteMe":30,
    "cars":{
      "car1":"Ford",
      "car2":"BMW",
      "deleteMe":"Fiat",
      "wheels":{
        "one":"Round",
        "two":"Square",
        "deleteMe":"Fiat"
        }
    }
  }
}

How could I delete every field with a name/key of "deleteMe". I do not know the structure of the object ahead of time.

F_SO_K
  • 13,640
  • 5
  • 54
  • 83

4 Answers4

4

You need to either find the key in the object or recursively descend into any value that is itself an object:

function deleteMe(obj, match) {
  delete obj[match];
  for (let v of Object.values(obj)) {
    if (v instanceof Object) {
      deleteMe(v, match);
    }
  }
}
Alnitak
  • 334,560
  • 70
  • 407
  • 495
3

const myObj =  {
  "name":"John",
  "deleteMe":30,
  "cars":{
    "car1":"Ford",
    "car2":"BMW",
    "deleteMe":"Fiat",
    "wheels":{
      "one":"Round",
      "two":"Square",
      "deleteMe":"Fiat"
      }
  }
}

const recursiveRemoveKey = (object, deleteKey) => {
  delete object[deleteKey];
  
  Object.values(object).forEach((val) => { 
    if (typeof val !== 'object') return;
    
    recursiveRemoveKey(val, deleteKey);
  })
}

recursiveRemoveKey(myObj, 'deleteMe');

console.log(myObj);
Abror Abdullaev
  • 269
  • 1
  • 6
2

You can recursively traverse each nested object and remove any keys you want at each level.

Note that this will modify the existing object.

const main = () => {
  console.log(pruneKeys(getData(), 'deleteMe'))
}

/** Wrapper */
const pruneKeys = (obj, ...keys) => {
  __pruneKeysInner(obj, new Set(keys.length && Array.isArray(keys[0])
    ? keys[0] : keys))
  return obj
}

/** Recursive call */
const __pruneKeysInner = (obj, keySet) => {
  if (obj != null && isObject(obj)) {
    for (key in obj) {
      if (keySet.has(key)) {
        delete obj[key]
      } else {
        __pruneKeysInner(obj[key], keySet)
      }
    }
  }
}

const isObject = n => Object.prototype.toString.call(n) === '[object Object]'

const getData = () => ({
  "myObj": {
    "name": "John",
    "deleteMe": 30,
    "cars": {
      "car1": "Ford",
      "car2": "BMW",
      "deleteMe": "Fiat",
      "wheels": {
        "one": "Round",
        "two": "Square",
        "deleteMe": "Fiat"
      }
    }
  }
})

main()
.as-console-wrapper {
  top: 0;
  max-height: 100% !important;
}
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
  • that's massively overcomplicated, and the use of `.includes` in the `forEach` is horribly inefficient. – Alnitak Jul 14 '20 at 12:37
  • This is great, thank you so much. I upvoted. – F_SO_K Jul 14 '20 at 12:41
  • @Alnitak That's because the function allows you to pass in multiple keys. If anything, it shows a better understanding of what's happening at each step. Anyone can take this an improve upon it. And I also like how I was down-voted for a working algorithm. This is not [Code Review](https://codereview.stackexchange.com/)... – Mr. Polywhirl Jul 14 '20 at 12:41
  • @Alnitak Anyways, I changed the `forEach` to a for-in loop and wrapped the keys in a set for more efficient look-ups. – Mr. Polywhirl Jul 14 '20 at 13:01
0

Something like this should work :

const obj = {
  "myObj":{
    "name":"John",
    "deleteMe":30,
    "cars":{
      "car1":"Ford",
      "car2":"BMW",
      "deleteMe":"Fiat",
      "wheels":{
        "one":"Round",
        "two":"Square",
        "deleteMe":"Fiat"
        }
    }
  }
}


const deleteField = (obj, field) => {
  Object.keys(obj).forEach((key) => {
    if (key === field) {
      delete obj[key];
    } else if (typeof obj[key] === "object") {
      deleteField(obj[key], field);
    }
  })
}

deleteField(obj, "deleteMe");
console.log(obj);

https://jsbin.com/gejunokisa/edit?html,js,output

Angel
  • 100
  • 8