0

I have a an Object and I need to delete all the "id" attributes inside at every deep level except for some of them.

I did this function:

const removeFieldFromObject = ({ obj, fieldName, ignoreFields = [] }) => {
  if (typeof obj !== "object" || obj === null) {
    return obj;
  }

  if (Array.isArray(obj)) {
    for (var i = 0; i < obj.length; i++) {
      obj[i] = removeFieldFromObject({ obj: obj[i], fieldName, ignoreFields });
    }
  } else {
    for (var prop in obj) {
      if (obj.hasOwnProperty(prop)) {
        if (prop === fieldName && !ignoreFields.includes(obj[prop])) {
          delete obj[prop];
        } else {
          obj[prop] = removeFieldFromObject({
            obj: obj[prop],
            fieldName,
            ignoreFields,
          });
        }
      }
    }
  }
  return obj;
};

If i invoke it with this object in the following way:

const obj = {
  id:1,
  data:{
    id:2,
    cards:{
      id:123,
      name:"my name",
      document:{
        id:2,
        url:"my url"
      }
    }
  }
}

const formattedObj = removeFieldFromObject({obj, fieldName: "id", ignoreFields: ["document"]})

It deletes the "id" attribute at all levels

I want it do remove all the attributes "id" except for document objects. This method removes them at every level. The reason is the condition on ignoreFields that is always true when it goes inside the document object and it checks the actual props. I looked around and found many similar questions but not with optional attributes.

Do you have any suggestion? I accept also solutions with lodash or similar.

1
  • I need to delete all the "id" attributes can't you just ignore them if you don't need them? Commented Oct 2, 2023 at 15:24

2 Answers 2

1
if (prop === fieldName && !ignoreFields.includes(obj[prop])) {
  delete obj[prop];
} else {
  obj[prop] = removeFieldFromObject(…);
}

This doesn't make a lot of sense - or at least, it doesn't match how you are calling the function. It checks for the value of the property to delete in the ignoreFields. What you actually want is to check the property name before doing the recursive call, so that nothing in .document does get visited:

if (prop === fieldName) {
  delete obj[prop];
} else if (!ignoreFields.includes(prop)) {
  obj[prop] = removeFieldFromObject(…);
}
Sign up to request clarification or add additional context in comments.

1 Comment

That's it! Thank you!
1

Could be something like this:

const removeFieldFromObject = ({obj, fieldName, ignoreFields}) => {

  if(Array.isArray(obj)) {
    arr.forEach(item => removeFieldsFromObject({obj, fieldName, ignoreFields}));
    return;
  }
  if(!Object.prototype.isPrototypeOf(obj)){
    return;
  }
  delete obj[fieldName];
  
  for(const k in obj){
    ignoreFields.includes(k) || removeFieldFromObject({obj: obj[k], fieldName, ignoreFields});
  }
};

removeFieldFromObject({obj, fieldName: "id", ignoreFields: ["document"]})

console.log(obj);
<script>
const obj = {
  id:1,
  data:{
    id:2,
    cards:{
      id:123,
      name:"my name",
      document:{
        id:2,
        url:"my url"
      }
    }
  }
}
</script>

9 Comments

Better avoid abusing short-circuiting operators for control flow, and avoid the deprecated __proto__
@Bergi what to use instead of proto? Object.getPrototypeOf() ?
Yes, exactly that
@Bergi isPrototypeOf could be event better i guess
What do you actually want to check? For just a primitive/object distinction the OPs typeof obj !== "object" || obj === null is fine (and does not miss undefined, albeit ignoring function objects, which seems sensible). If you want to include function objects, use Object(obj) === obj. Or do you want to check for "plain" objects, i.e. those that don't have a custom prototype like class instances?
|

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.