Arrstad
Arrstad

Reputation: 190

Collect all paths in JSON object

I'm dealing with the following JavaScript object:

{
    "gender": "man",
    "jobinfo": {
        "type": "teacher"
    },
    "children": [
        {
            "name": "Daniel",
            "age": 12,
            "pets": [
                {
                    "type": "cat", 
                    "name": "Willy",
                    "age": 2
                },
                {
                    "type": "dog", 
                    "name": "Jimmie",
                    "age": 5
                }
            ]
        }
    ]
}

I want to print out each of the paths (keys and array indices) within the object, including the parents (i.e. children should be printed as should everything in it).

gender
jobinfo,
jobinfo.type,
children,
children.0.name,
children.0.age,
children.0.pets,
children.0.pets.0.type,
children.0.pets.0.name,
children.0.pets.0.age,
children.0.pets.1.type,
children.0.pets.1.name,
children.0.pets.1.age

I tried this code with modifications but it didnt work for me:

function getPath(object) {
    for (key in object) {
        if (Array.isArray(object[key]) === true) {
            console.log(key)
            getPath(object[key])
        } else if (typeof object[key] === 'object') {
            console.log(key)
            getPath(object[key])
        } else {
            console.log(key)
        }
    }
}

It's printing all keys in the JSON, but I'm struggling with joining the paths, especially in nested elements.

Upvotes: 0

Views: 1508

Answers (2)

efkan
efkan

Reputation: 13227

In this version array keys that are consisted of numbers like 'children.0' and so on handled and this gives the result exactly what you wanted:

const json = {"gender":"man","jobinfo":{"type":"teacher"},"children":[{"name":"Daniel","age":12,"pets":[{"type":"cat","name":"Willy","age":2},{"type":"dog","name":"Jimmie","age":5}]}]};

function getPath(object, previousPath) {
  for (key in object) {
    let currentPath = previousPath ? `${previousPath}.${key}` : key

    if (Array.isArray(object[key])) {
      console.log(currentPath)
      getPath(object[key], currentPath)
    } else if (typeof object[key] === 'object') {
      if (!Array.isArray(object)) { // skipping logging array keys like children.0
        console.log(currentPath)
      }
      getPath(object[key], currentPath)
    } else {
      console.log(currentPath)
    }
  }
}

getPath(json)

Upvotes: 2

Jack Bashford
Jack Bashford

Reputation: 44105

This works:

const data = {"gender":"man","jobinfo":{"type":"teacher"},"children":[{"name":"Daniel","age":12,"pets":[{"type":"cat","name":"Willy","age":2},{"type":"dog","name":"Jimmie","age":5}]}]};

const getPath = (currPath, item) => {
  console.log(currPath);
  if (Array.isArray(item)) {
    item.forEach((el, idx) => getPath(`${currPath}.${idx}`, el));
  } else if (typeof item == "object") {
    Object.entries(item).forEach(([key, value]) => {
      getPath(`${currPath}.${key}`, value);
    });
  }
};

Object.entries(data).forEach(([key, value]) => {
  getPath(key, value);
});

Basically I just loop through each of the entries in the initial object, using the key as the path at that stage and checking if the value is an object or array. I always print the path within the function (to provide the outer layers you want) and then I recurse over the inner layers, adding to the path as needed.

Upvotes: 2

Related Questions