13

Let's say I have nested objects, like:

var obj = {
    "items":[
        {
            "name":"Item 1", 
            "value": "500",
            "options": [{...},{...}]
        },
        {
            "name":"Item 2", 
            "value": "300",
            "options": [{...},{...}]
        }
    ],
    "name": "Category",
    "options": [{...},{...}]
};

I want to remove the options property from any level deep from all the objects. Objects can be nested within objects, and arrays as well.

We're currently using Lodash in the project, but I'm curious about any solutions.

1

7 Answers 7

9

There is no straight forward way to achieve this, however you can use this below function to remove a key from JSON.

function filterObject(obj, key) {
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            filterObject(obj[i], key);
        } else if (i == key) {
            delete obj[key];
        }
    }
    return obj;
}

and use it like

var newObject = filterObject(old_json, "option");
Sign up to request clarification or add additional context in comments.

5 Comments

Hmm our codebase is in strict mode, and I'm getting the following error: Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
@void is there a way to do this without recursion, I keep getting 'RangeError: Maximum call stack size exceeded' even with the similar solution posted here softwareengineering.stackexchange.com/a/323670
@erotavlas maybe you need to pass only a part of the object and not the complete object. This will reduce the number of iterations.
It seems delete key; should be delete obj[key];
if key contains object as value then @sboyd solution here is better structured.
6

A little modification of void's answer that allows for deletion of propertise which are also objects

function filterObject(obj, key) {
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (i == key) {
            delete obj[key];
        } else if (typeof obj[i] == 'object') {
            filterObject(obj[i], key);
        }
    }
    return obj;
}

Comments

6

Modifying the above solution, To delete "dataID" which appears multiple times in my JSON . mentioned below code works fine.

var candidate = {
  "__dataID__": "Y2FuZGlkYXRlOjkuOTI3NDE5MDExMDU0Mjc2",
  "identity": {
    "__dataID__": "aWRlbnRpdHk6NjRmcDR2cnhneGE3NGNoZA==",
    "name": "Sumanth Suvarnas"
  },  
};

candidate = removeProp(candidate, "__dataID__")

console.log(JSON.stringify(candidate, undefined, 2));

function removeProp(obj, propToDelete) {
   for (var property in obj) {
      if (typeof obj[property] == "object") {
         delete obj.property
         let newJsonData= this.removeProp(obj[property], propToDelete);
         obj[property]= newJsonData
      } else {
          if (property === propToDelete) {
            delete obj[property];
          }
        }
    }
    return obj
}

1 Comment

is delete obj.property a typo?
3

We now use object-scan for data processing tasks like this. It's very powerful once you wrap your head around it. Here is how you'd answer your questions

// const objectScan = require('object-scan');

const prune = (input) => objectScan(['**.options'], {
  rtn: 'count',
  filterFn: ({ parent, property }) => {
    delete parent[property];
  }
})(input);

const obj = { items: [{ name: 'Item 1', value: '500', options: [{}, {}] }, { name: 'Item 2', value: '300', options: [{}, {}] }], name: 'Category', options: [{}, {}] };

console.log(prune(obj));
// => 3

console.log(obj);
// => { items: [ { name: 'Item 1', value: '500' }, { name: 'Item 2', value: '300' } ], name: 'Category' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

Comments

1

I had a similar issue and I got it resolved. I hope my solution might be helpful to someone.

I use Es6 ... spread operator to do a shallow copy of an object and made null to property I was not interested.

const newObject = {
   ...obj.items,
   ...obj.name,
   options: null // option property will be null.
}

2 Comments

undefined would be more accurate, as you're removing info
This does not work for the "any level" part of the question. You do mention it's shallow, but that's not the question.
1
function omit(source) {
  return isArray(source)
    ? source.map(omit)
    : isObject(source)
    ? (({ options, ...rst }) => mapValues(rst, omit))(source)
    : source;
}

as with lodash, that's an easy thing, also you can specify the key via an param like this

function omit(source, omitKey) {
  return isArray(source)
    ? source.map(partialRight(omit,omitKey)))
    : isObject(source)
    ? (({[omitKey]: _, ...rst }) => mapValues(rst, partialRight(omit,omitKey)))(source)
    : source;
}

Comments

1

You can remove properties given a condition using following function:

// Warning: this function mutates original object
const removeProperties = (obj, condition = (key, value) => false) => {
  for (var key in obj) {
    const value = obj[key]
    if (!obj.hasOwnProperty(key)) continue
    if (typeof obj[key] === "object") {
      removeProperties(obj[key], condition)
    } else if (condition(key, value)) {
      delete obj[key]
    }
  }
  return obj
}

Examples:

// Remove all properties where key is equal to 'options'
removeProperties(someObject, (key, value) => key === 'options'))


// Remove all properties where key starts with 'ignore_'
removeProperties(someObject, (key, value) => key.startsWith('ignore_'))


// Remove all properties where value is null
removeProperties(someObject, (key, value) => value === null))

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.