0

I have the following JSON of structured, nested data.

[
  {
    "id": "2e270ad7-90aa-41da-bb57-a777448f5906",
    "name": "First Level 1",
    "childValues": [
      {
        "id": "4cecbd28-fd06-4c2a-9b57-33d4a298675c",
        "name": "Second Level 1 "
      },
      {
        "id": "09893799-e21c-498f-96b4-e63e366a3c18",
        "name": "Second Level 2"
      }
    ]
  },
  {
    "id": "18889675-9d71-420e-84a6-3603af044b6c",
    "name": "First Level 2",
    "childValues": [
      {
        "id": "b7093ca1-5fed-4eb2-b934-637bfdc6c7da",
        "name": "Second Level 3"
      },
      {
        "id": "a3575212-1746-4dd3-ab52-4e37786c035c",
        "name": "Second Level 4"
      }
    ]
  },
  {
    "id": "71113ffb-62f0-4d76-941f-974be3cd35cb",
    "name": "First Level 3",
    "childValues": [
      {
        "id": "160570a5-29aa-4fdb-bb16-d9d7637d0177",
        "name": "Second Level 5",
        "childValues": [
          {
            "id": "2df28cb9-9ac4-478c-a2a4-6dc5206c983b",
            "name": "Third Level 1"
          },
          {
            "id": "a974cfac-1e2c-461c-ab64-0f5dd9d1cf1e",
            "name": "Third Level 2"
          }
        ]
      },
      {
        "id": "6e5947ea-2c47-4d2b-8ecd-6369c728e7db",
        "name": "Second Level 6"
      }
    ]
  }
]

I am trying to extract an array of objects from this nested array structure based on a level of nesting. For instance, level 0 just gives me back all of the base object in the array, but if I ask for level 1, I am trying to get back an output of just the second level nested objects, under the childValues property, in a single array, like the following:

[
  {
    "id": "4cecbd28-fd06-4c2a-9b57-33d4a298675c",
    "name": "Second Level 1 "
  },
  {
    "id": "09893799-e21c-498f-96b4-e63e366a3c18",
    "name": "Second Level 2"
  },
  {
    "id": "b7093ca1-5fed-4eb2-b934-637bfdc6c7da",
    "name": "Second Level 3"
  },
  {
    "id": "a3575212-1746-4dd3-ab52-4e37786c035c",
    "name": "Second Level 4"
  },
  {
    "id": "160570a5-29aa-4fdb-bb16-d9d7637d0177",
    "name": "Second Level 5",
    "childValues": [
      {
        "id": "2df28cb9-9ac4-478c-a2a4-6dc5206c983b",
        "name": "Third Level 1"
      },
      {
        "id": "a974cfac-1e2c-461c-ab64-0f5dd9d1cf1e",
        "name": "Third Level 2"
      }
    ]
  },
  {
    "id": "6e5947ea-2c47-4d2b-8ecd-6369c728e7db",
    "name": "Second Level 6"
  }
]

And if I ask for level 2, I should only get the third level objects:

[
  {
    "id": "2df28cb9-9ac4-478c-a2a4-6dc5206c983b",
    "name": "Third Level 1"
  },
  {
    "id": "a974cfac-1e2c-461c-ab64-0f5dd9d1cf1e",
    "name": "Third Level 2"
  }
]

The only thing I have figured out is how to completely flatten the structure recursively, but cant put my finger on how to extract a specific level.

private flat(array: any[]) {
  let result: any[] = [];
  array.forEach((a) => {
    result.push(a);
    if (Array.isArray(a.childValues)) {
      result = result.concat(this.flat(a.childValues));
    }
  });
  return result;
}
0

4 Answers 4

1

Here's a cleaner version of Shane Padgett's function:

const getArrayByNthLevel = (array, levelToGet, currentLevel=0) => array.reduce((retval, a) => {
        levelToGet === currentLevel
            ? retval.push(a)
            : Array.isArray(a.childValues)
                ? retval = retval.concat(getArrayByNthLevel(a.childValues, levelToGet, currentLevel + 1))
                : false
        return retval;
    }, []);
Sign up to request clarification or add additional context in comments.

1 Comment

I like this answer. Clean version of my code that doesnt need shims to work on all browsers.
1

I was able to achieve this with the following function.

function getArrayByNthLevelOfPropName(array, propName, levelToGet, currentLevel = 0) {
  let result = [];
  array.forEach((a) => {
    if (levelToGet === currentLevel) {
      result.push(a);
    }

    if (Array.isArray(a[propName]) && levelToGet !== currentLevel) {
      result = result.concat(getArrayByNthLevelOfPropName(a[propName], propName, levelToGet, ++currentLevel));
      currentLevel -= 1;
    }
  });

  return result;
}

Comments

1

You can use flatMap like this:

const input=[{id:"2e270ad7-90aa-41da-bb57-a777448f5906",name:"First Level 1",childValues:[{id:"4cecbd28-fd06-4c2a-9b57-33d4a298675c",name:"Second Level 1 "},{id:"09893799-e21c-498f-96b4-e63e366a3c18",name:"Second Level 2"}]},{id:"18889675-9d71-420e-84a6-3603af044b6c",name:"First Level 2",childValues:[{id:"b7093ca1-5fed-4eb2-b934-637bfdc6c7da",name:"Second Level 3"},{id:"a3575212-1746-4dd3-ab52-4e37786c035c",name:"Second Level 4"}]},{id:"71113ffb-62f0-4d76-941f-974be3cd35cb",name:"First Level 3",childValues:[{id:"160570a5-29aa-4fdb-bb16-d9d7637d0177",name:"Second Level 5",childValues:[{id:"2df28cb9-9ac4-478c-a2a4-6dc5206c983b",name:"Third Level 1"},{id:"a974cfac-1e2c-461c-ab64-0f5dd9d1cf1e",name:"Third Level 2"}]},{id:"6e5947ea-2c47-4d2b-8ecd-6369c728e7db",name:"Second Level 6"}]}];

const getLevel = (arr = [], required, current = 0) =>
    required === current 
      ? arr
      : arr.flatMap(a => getLevel(a.childValues, required, current + 1))

console.log("Second Level: \n ", getLevel(input, 1))
console.log("Third Level: \n ", getLevel(input, 2))

If flatMap is not supported, you can use

[].concat(...arr.map(a => getLevel(a.childValues, required, current + 1)))

2 Comments

I like this but it doesnt look to support all browsers.
@ShanePadgett you can use concat as mentioned in the answer or you can add a polyfill for flatMap (It's supported in Chrome and Firefox. IE doesn't have support for Arrow functions as well)
0

Following should work:

var data = [
  {
    "id": "2e270ad7-90aa-41da-bb57-a777448f5906",
    "name": "First Level 1",
    "childValues": [
      {
        "id": "4cecbd28-fd06-4c2a-9b57-33d4a298675c",
        "name": "Second Level 1"
      },
      {
        "id": "09893799-e21c-498f-96b4-e63e366a3c18",
        "name": "Second Level 2"
      }
    ]
  },
  {
    "id": "18889675-9d71-420e-84a6-3603af044b6c",
    "name": "First Level 2",
    "childValues": [
      {
        "id": "b7093ca1-5fed-4eb2-b934-637bfdc6c7da",
        "name": "Second Level 3"
      },
      {
        "id": "a3575212-1746-4dd3-ab52-4e37786c035c",
        "name": "Second Level 4"
      }
    ]
  },
  {
    "id": "71113ffb-62f0-4d76-941f-974be3cd35cb",
    "name": "First Level 3",
    "childValues": [
      {
        "id": "160570a5-29aa-4fdb-bb16-d9d7637d0177",
        "name": "Second Level 5",
        "childValues": [
          {
            "id": "2df28cb9-9ac4-478c-a2a4-6dc5206c983b",
            "name": "Third Level 1"
          },
          {
            "id": "a974cfac-1e2c-461c-ab64-0f5dd9d1cf1e",
            "name": "Third Level 2"
          }
        ]
      },
      {
        "id": "6e5947ea-2c47-4d2b-8ecd-6369c728e7db",
        "name": "Second Level 6"
      }
    ]
  }
];

function getData(data, targetLevel, currentLevel = 0) {
    // If this is the target level, then extract the
    // data we need from each item, and return the array
    if (currentLevel == targetLevel) {
        return data;
    }
    // Otherwise, run a map over the items, and if they have
    // 'childValues', then recurs, but increment the value of
    // 'current level' it will be iterating on
    // Because 'map' will return array of array, merge them
    // to a single array
    return [].concat(...data.map(item => {
        if (item.childValues) {
            return getData(item.childValues, targetLevel, currentLevel + 1);
        };
        return [];
    }));
}

document.getElementById("dataLevel0").innerHTML = JSON.stringify(getData(data, 0), null, 4);
document.getElementById("dataLevel1").innerHTML = JSON.stringify(getData(data, 1), null, 4);
document.getElementById("dataLevel2").innerHTML = JSON.stringify(getData(data, 2), null, 4);
<div>
Level 1:
</div>
<pre id="dataLevel0">
</pre>
<div>
Level 2:
</div>
<pre id="dataLevel1">
</pre>
<div>
Level 3:
</div>
<pre id="dataLevel2">
</pre>

2 Comments

This version hard codes the returned map. I think the idea is to return the entire object at the level regardless of its contents.
"Hard coding the map" seems like the wrong phrase here I think. I got what you were pointing out though, thanks for that! Missed reading that one.

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.