skip to Main Content

I have this object:

{
    "id": "e8546367-d643-4da0-80dc-0980c9935ded",
    "offsetSeconds": 86400,
    "tasks": {
        "id": "contactChampionInitialTalk",
        "icon": "0",
        "skills": [
            "skillCommunityManager"
        ],
        "name": {
            "en": "Contact Champion"
        },
        "description": {
            "en": "Initial talk, agreement on the theme, and potentiel availabilities for the event"
        }
    }
}

And I want to recursively go through it using JavaScript/TypeScript to get:

{
    "id": "e8546367-d643-4da0-80dc-0980c9935ded",
    "offsetSeconds": 86400,
    "tasks": {
        "id": "contactChampionInitialTalk",
        "icon": "0",
        "skills": [
            "skillCommunityManager"
        ],
        "name": "Contact Champion",
        "description":"Initial talk, agreement on the theme, and potentiel availabilities for the event"
    }
}

How can I do that? I have an array of multiple objects like this one

This function works but only for level 1 entries:

const replaceNestedValue = (obj, targetKey) => {
    const newObj = { ...obj };

    Object.entries(newObj).forEach(([key, value]) => {
      if (value && typeof value === 'object' && !Array.isArray(value) && value[targetKey]) {
        newObj[key] = value[targetKey];
      }
    });

    return newObj;
  };

2

Answers


  1. You are checking for the targetKey too early. As you need to process the input recursively you should apply your function for any nested object. And targetKey should only control actual replacement. For the innermost part something like this:

      if (value && typeof value === 'object' && !Array.isArray(value)) {
        if(targetKey in value)
            newObj[key] = value[targetKey];
        else
            replaceNestedObjectValue(value, targetKey);
      }
    

    Personally, I’d rather rewrite the function to not operate in-place but return the adjusted result.

    Login or Signup to reply.
  2. You would need to first check what the data type is of the first argument (primitive, array or (other) object), and for each of these three categories determine what to do:

    • Primitive: just return the input
    • Array: map the array by calling the function recursively on all its elements.
    • Other: create a new object, with the logic of "lifting" the targetkey from a child object to its parent.

    Code:

    const liftTargetKey = (value, targetKey) => 
        // Primitive:
        Object(value) !== value ? value 
        // Array:
      : Array.isArray(value) ? value.map(obj => liftTargetKey(obj, targetKey)) 
        // Plain object:
      : Object.fromEntries(Object.entries(value).map(([key, val]) => 
            [key, val?.en ?? liftTargetKey(val, targetKey)]
        ));
    
    // Example run
    const inputArray = [{
        "id": "e8546367-d643-4da0-80dc-0980c9935ded",
        "offsetSeconds": 86400,
        "tasks": {
            "id": "contactChampionInitialTalk",
            "icon": "0",
            "skills": [
                "skillCommunityManager"
            ],
            "name": {
                "en": "Contact Champion"
            },
            "description": {
                "en": "Initial talk, agreement on the theme, and potentiel availabilities for the event"
            }
        }
    }];
    
    console.log(liftTargetKey(inputArray, "en")); 

    This solution considers the input immutable, i.e. it does not modify the original input, but returns new objects/arrays where mutation is needed.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search