3

I hope that someone can help me with the following.

I want to traverse through a deeply nested JSON-object and generate a dictionary with the traversed path and corresponding value(s).

My object looks like this:

{
  title: 'Mr.',
  user: {
    address: {
      city: 'Amsterdam'
    },
    name: {
      first: 'MyFirstName',
      last: 'MyLastName'
    }
  }
}

The result I'm after looks like this:

{
  'title': 'Mr.',
  'user.address.city': 'Amsterdam',
  'user.name.first': 'MyFirstName',
  'user.name.last': 'MyLastName'
}

I used Object.Entries method to traverse through key/value pairs and used recursion to generate an Array of keys, but it doesn't handle siblings on deeper levels very well...

I already looked at "Traverse all the Nodes of a JSON Object Tree with JavaScript ", but it didn't solve my problem since I want to generate a dictionary where the traversed path is the key and where the deepest node is the value.

I want to stress that I'm looking for a native JavaScript solution without any framework or library.

The current result is:

[
  "user.address.city",
  "user.name.first,name.last",
  "user.occupation.job.description.name,description.title"
]

My code:

const obj = {
  title: 'Mr.',
  user: {
    address: {
      city: 'Amsterdam'
    },
    name: {
      first: 'MyFirstName',
      last: 'MyLastName'
    }
  }
};

const isObject = (obj) => Object.prototype.toString.call(obj).indexOf("Object") > -1;

const generateBindingKeys = (key, obj) => {
  //return an array of keybindings, because there can be more siblings in one node
  return Object.keys(obj).map(k => isObject(obj[k]) ? `${key}.${generateBindingKeys(k, obj[k])}` : `${key}.${k}`);
};

// traverse all entries in the new state
Object.entries(obj).forEach(([key, val]) => {
  // generate the binding
  // if there are children we need to recursively traverse through the path and return the keys
  const bindings = isObject(val) ? generateBindingKeys(key, val) : key;
  console.log(bindings);
});
StefanN
  • 871
  • 6
  • 19
  • Where are `occupation`, `job` and `description` coming from? – Scott Hunter Aug 26 '19 at 12:12
  • This is part of an application that generates bindings from a state (`obj`), provided by users. So the structure and nesting of the object can differ enormously. – StefanN Aug 26 '19 at 12:14
  • It's no duplicate of that story since I'm trying to generate a dictionary where the path is the key and the deepest entry of a path is the value. – StefanN Aug 26 '19 at 12:18
  • So, what's the trouble here? Seems like you almost did it. Just switch from array to object and use the values from your example as keys – lucifer63 Aug 26 '19 at 12:26
  • True, I'm almost there, but I just can't get my head around it. – StefanN Aug 26 '19 at 12:33
  • 3
    @StefanN - Check flatten JSON structure [link](https://stackoverflow.com/a/19101235/2932057) – Nareen Babu Aug 26 '19 at 12:35
  • Thanks! This is a really nice solution that meets my needs :) – StefanN Aug 26 '19 at 12:50

2 Answers2

2

You can achieve that by making a recursive function. Check below snippet.

  const object = {
    title: 'Mr.',
    user: {
address: {
  city: 'Amsterdam',
},
name: {
  first: 'MyFirstName',
  last: 'MyLastName',
},
    },
  };
  
  
  function getKeyNames(obj, lastStored, secondObj) {
    Object.keys(obj).forEach((r) => {
      const elem = obj[r];
      const refObj = secondObj;
      const key = lastStored ? `${lastStored}.${r}` : r;
      if (!Array.isArray(elem)) {
        if (typeof elem !== 'object') {
          refObj[key] = elem;
        }
      }
      if (typeof elem === 'object' && (!Array.isArray(elem))) {
        getKeyNames(elem, key, secondObj);
      }
    });
    return secondObj;
  }
  
  function getAllKeys(obj) {
    const secondObj = {};
    const keys = getKeyNames(obj, '', secondObj);
    return keys;
  }
  
  const result = getAllKeys(object);
  console.log(result);

Note: Not work when any key consist []

Neel Rathod
  • 2,013
  • 12
  • 28
0

Just traverse and store values to a new object like this:

<script>
var jsond = {
    title: 'Mr.',
    user: {
        address: {
            city: 'Amsterdam'
        },
        name: {
            first: 'MyFirstName',
            last: 'MyLastName'
        }
    }
}

var newJson = {};

if(jsond.length!=0){
    jQuery.each(jsond, function (i, val) {
        if(typeof val==="object"){
            jQuery.each(val, function (subi, subval) {


                if(typeof subval==="object"){
                    jQuery.each(subval, function (verysubi, verysubval) {


                        newJson[verysubi] = verysubval;

                    });
                }else{
                    newJson[subi] = subval;
                }

            });
        }else{
            newJson[i] = val;
        }
    });
}

console.log(newJson);
</script>

You can assign user.address or any other key too by checking possible values.

Den Pat
  • 1,118
  • 10
  • 17
  • Thanks for your answer, but this solution only works with a fixed number of nesting. I need it to work for any number of nesting and I'm looking for a native solution without libraries like JQuery. – StefanN Aug 26 '19 at 12:36