Using JavaScript what's the quickest way to recursively remove properties and values from an object?
Asked Answered
C

9

33

I need to find the fastest way to remove all $meta properties and their values from an object, for example:

{
  "part_one": {
    "name": "My Name",
    "something": "123",
    "$meta": {
      "test": "test123"
    }
  },
  "part_two": [
    {
      "name": "name",
      "dob": "dob",
      "$meta": {
        "something": "else",
        "and": "more"
      }
    },
    {
      "name": "name",
      "dob": "dob"
    }
  ],
  "$meta": {
    "one": 1,
    "two": 2
  }
}

Should become the following given that the $meta property could be at any point in the object so some form of recursion will probably be needed.

{
  "part_one": {
    "name": "My Name",
    "something": "123"
  },
  "part_two": [
    {
      "name": "name",
      "dob": "dob"
    },
    {
      "name": "name",
      "dob": "dob"
    }
  ]
}
Confessional answered 30/7, 2015 at 16:14 Comment(3)
Instead of using recursion, make a copy of the object omitting the properties and values you don't want. A general note about recursion in javascript: It depends on the browsers memory allocation which isn't much so recursion is resource heavy and won't work for large data sets unless careful memory management is implemented.Virnelli
The fastest way is to implement it yourself first, then ask for help on making it faster.Ljubljana
You can can traverse an object properties and values with the use of a for in loop or better said for of --> developer.mozilla.org/en/docs/Web/JavaScript/Reference/…Virnelli
D
47

A simple self-calling function can do it.

function removeMeta(obj) {
  for(prop in obj) {
    if (prop === '$meta')
      delete obj[prop];
    else if (typeof obj[prop] === 'object')
      removeMeta(obj[prop]);
  }
}

var myObj = {
  "part_one": {
    "name": "My Name",
    "something": "123",
    "$meta": {
      "test": "test123"
    }
  },
  "part_two": [
    {
      "name": "name",
      "dob": "dob",
      "$meta": {
        "something": "else",
        "and": "more"
      }
    },
    {
      "name": "name",
      "dob": "dob"
    }
  ],
  "$meta": {
    "one": 1,
    "two": 2
  }
}

function removeMeta(obj) {
  for(prop in obj) {
    if (prop === '$meta')
      delete obj[prop];
    else if (typeof obj[prop] === 'object')
      removeMeta(obj[prop]);
  }
}

removeMeta(myObj);

console.log(myObj);
Dorweiler answered 30/7, 2015 at 16:28 Comment(3)
until JS has tail recursion optimization this is not safe for large objects. It's also unsafe for objects with circular references.Eyebright
works perfectly, just be sure to clone the object if you need to preserve the original one.Anthocyanin
I don't see it working for me. This takes just the first property if that's an object. What about the others? It will not return me the whole object with eliminating that particular prop. Or where am I missing?Ashanti
E
44

As @floor commented above:

JSON.parse(JSON.stringify(obj, (k,v) => (k === '$meta')? undefined : v))

Eyebright answered 13/9, 2016 at 1:44 Comment(2)
Rather, provide the replacer as an argument to the stringify call, thus avoiding serializing these properties into string to begin withChrestomathy
Warning that this method will remove unserializable content from the object, like functions or DOM elements, for exampleSpeculation
A
28

// Helper function
function removeProps(obj,keys){
  if(Array.isArray(obj)){
    obj.forEach(function(item){
      removeProps(item,keys)
    });
  }
  else if(typeof obj === 'object' && obj != null){
    Object.getOwnPropertyNames(obj).forEach(function(key){
      if(keys.indexOf(key) !== -1)delete obj[key];
      else removeProps(obj[key],keys);
    });
  }
}
// The object we want to iterate
var obj = {
  "part_one": {
    "name": "My Name",
    "something": "123",
    "$meta": {
      "test": "test123"
    }
  },
  "part_two": [
    {
      "name": "name",
      "dob": "dob",
      "$meta": {
        "something": "else",
        "and": "more"
      }
    },
    {
      "name": "name",
      "dob": "dob"
    }
  ],
  "$meta": {
    "one": 1,
    "two": 2
  }
};
// Utilize the utility
removeProps(obj,['$meta']);
// Show the result
document.body.innerHTML = '<pre>' + JSON.stringify(obj,null,4) + '</pre>';
Arvo answered 30/7, 2015 at 16:27 Comment(2)
Smart way to achieve that in pure js at any level, thank you!Outermost
It worked!, thanks.Rasberry
P
4

I created this functions when any key is in any level in the object using the reference function of @Joseph Marikle

const _ = require("lodash");
const isObject = obj => obj != null && obj.constructor.name === "Object";
const removeAttrDeep = (obj, key) => {
    for (prop in obj) {
      if (prop === key) delete obj[prop];
      else if (_.isArray(obj[prop])) {
        obj[prop] = obj[prop].filter(k => {
          return !_.isEmpty(removeAttrDeep(k, key));
        });
     } else if (isObject(obj[prop])) removeAttrDeep(obj[prop], key);
    }
    return obj;
 };

EXAMPLE:

 const _obj = {
       a: "b", b: "e", c: { a: "a", b: "b", c: "c"},
       d: [ { a: "3" }, { b: ["2", "3"] }]};
 console.log(removeAttrDeep(_obj, "b"));
Powerless answered 4/10, 2019 at 20:56 Comment(0)
B
3

(Apologies, I do not yet have enough reputation points to comment directly.)

Just FYI, typeof null === 'object', so in the removeMeta() example offered by @joseph-marikle, the function will recurse on a null value.

Read more here: why is typeof null "object"?

Boom answered 22/8, 2017 at 20:32 Comment(0)
F
2

Here is a function that takes either a string or an array of strings to remove recursively (based on Joseph's answer):

// removes all propsToRemove (passed as an array or string), drilling down up to maxLevel times
// will modify the input and return it
du.removeAllPropsFromObj = function(obj, propsToRemove, maxLevel) {
    if (typeof maxLevel !== "number") maxLevel = 10
    for (var prop in obj) {
        if (typeof propsToRemove === "string" && prop === propsToRemove)
            delete obj[prop];
        else if (propsToRemove.indexOf(prop) >= 0)      // it must be an array
            delete obj[prop];
        else if (typeof obj[prop] === "object" && maxLevel>0)
            du.removeAllPropsFromObj(obj[prop], propsToRemove, maxLevel-1);
    }
    return obj
}
Firelock answered 30/7, 2018 at 20:39 Comment(0)
A
2
// recursively delete a key from anywhere in the object
// will mutate the obj - no need to return it
const deletePropFromObj = (obj, deleteThisKey) => {
  if (Array.isArray(obj)) {
    obj.forEach(element => deletePropFromObj(element, deleteThisKey))
  } else if (typeof obj === 'object') {
    for (const key in obj) {
      const value = obj[key]
      if (key === deleteThisKey) delete obj[key]
      else deletePropFromObj(value, deleteThisKey)
    }
  }
}

deletePropFromObj(obj, '$meta');
Apostrophize answered 11/2, 2020 at 3:42 Comment(0)
K
2

This should avoid any issues with circular references

const recursiveRedact = <T extends Object>(obj: T, keys: Set<string>, visitedIn?: Set<any>): T => {
  if (obj == null || typeof obj !== 'object') return obj;
  const visited = visitedIn ?? new Set();
  visited.add(obj);
  Object.entries(obj).forEach(([key, val]) => {
    if (keys.has(key)) {
      obj[key as keyof T] = '[redacted]' as any;
    } else if (typeof val === 'object' && !visited.has(val)) {
      recursiveRedact(val, keys, visited);
    }
  });
  return obj;
};
Klute answered 3/6, 2022 at 18:40 Comment(2)
Thanks a lot. That is exactly what I was looking for. I wanted to write an object to a json file and it failed due to circular dependencies. Using your function fixed my issue.Bugger
@MinaLuke glad I was able to help! Good thing you commented too. The code above ended up needing a fix to account for typeof null == "object" so I'll update the answer nowKlute
A
1

Just sharing my solution:

export const removePropFromObject = (
  obj: Record<string, any>,
  prop: string
) => {
  if (!obj) return {};
  const copyObj = JSON.parse(JSON.stringify(obj));
  Object.keys(copyObj).forEach((key: string) => {
    if (key === prop) {
      delete copyObj[key];
    } else if (typeof copyObj[key] === 'object') {
      copyObj[key] = removePropFromObject(copyObj[key], prop);
    }
  });
  return copyObj;
};
Archivolt answered 2/7 at 21:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.