Home > Blockchain >  Collect all paths in JSON object
Collect all paths in JSON object

Time:06-11

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.

CodePudding user response:

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.

CodePudding user response:

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)) {
        console.log(currentPath)
      }
      getPath(object[key], currentPath)
    } else {
      console.log(currentPath)
    }
  }
}

getPath(json)

CodePudding user response:

I believe you are looking for a flattening function. I think this answer may help you

  • Related