1

I have a nested object, how do I have function that you pass in the object and a key and get back the value?

Example Inputs

object = {"a1":{"b1":"{"c1":"d1"}"}}
key = a1/b1/c1
object = {"x1":{"y1":"{"z1":"a1"}"}}
key = x1/y1/z1
value = a1

Below is what I have attempted but it's wrong

var obj, traverse;

obj = {
  a1: {
    b1: c1,
    b1: d1
  },
  x1: {
    y1: z1,
    y1: a1
  }
};

traverse = function(node, path) {
  var pairs;
  if (!(pairs = _(node).pairs()).length) {
    return [
      {
        keys: path,
        value: node
      }
    ];
  } else {
    return [].concat.apply([], _(pairs).map(function(kv) {
      return traverse(kv[1], path.concat(kv[0]));
    }));
  }
};

console.log(traverse(obj, []));
barbsan
  • 3,418
  • 11
  • 21
  • 28
GJ_Trader
  • 13
  • 1
  • 3
  • Possible duplicate of [Convert JavaScript string in dot notation into an object reference](https://stackoverflow.com/questions/6393943) – adiga Jul 03 '19 at 11:01
  • ^ Instead of splitting at `.`, split at backslash (`\\`) – adiga Jul 03 '19 at 11:02

3 Answers3

1

If you can express your keys as an array you can solve this with a reduce:

const obj = {"x1":{"y1":{"z1":"a1"}}}

const keys = ['x1', 'y1', 'z1']


const value = keys.reduce((acc,key)=>acc[key], obj)// "a1"

As a function that accepts an array of keys or a string of the form 'x1.y1.z1', with a fallback for undefined values:

const getValueFromKeys = (obj, keys, defaultValue)=> (Array.isArray(keys)?keys:keys.split('.')).reduce((acc,key)=>acc[key] || defaultValue, obj)
Will Jenkins
  • 9,507
  • 1
  • 27
  • 46
0

You could try lodash _.get , it's brilliant for this type of access:

What's nice too is you can pass in a default value if the path is not found.

var object = {"a1": { "b1": { "c1": "d1" }}};

console.log("Result at 'a1.b1.c1': ",_.get(object, 'a1.b1.c1'));
console.log("Result at 'a1.b1.nonexistent key': ",_.get(object, 'a1.b1.nonexistent', "default result"));

var object2 = {"x1":{"y1":{"z1":"a1"}}};
console.log("Result at 'x1.y1.z1': ",_.get(object2, 'x1.y1.z1'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
  • 1
    Thanks this is very comprehensive. I need to read more about the loadstash you suggested. If you dont mind can you tell me how the default value works? – GJ_Trader Jul 03 '19 at 11:05
  • So the default value is what is returned if the key / path cannot be found. If you don't supply a default value _undefined_ is returned instead. The lodash docs have some good info on this function as well: https://lodash.com/docs/4.17.11#get ! I find it very useful for working with deeply nested objects. – Terry Lennox Jul 03 '19 at 11:08
0
let obj = {
    a1: {
        b1: {
            nested: true
        },
    },
    x1: {
        y1: 'zl',
    }
};


function getObjectKeys(object, key) {
    // if you want another split key you can change this.
    const keys = key.split('.');
    let obj = object;
    for (let ikey of keys) {
        for (let [objKey, value] of Object.entries(obj)) {
            if(!keys.includes(objKey)) {
                continue;
            }
            obj = value;
        }
    }
    return obj;
}

console.log(getObjectKeys(obj, 'a1.b1.nested'));

console.log(getObjectKeys(obj, 'x1.y1'));
// even if there is another additional key
console.log(getObjectKeys(obj, 'x1.y1.nested'));

Without using any library, read more about Object.entries

Jamal Abo
  • 472
  • 4
  • 16