1

Instead of using object literal syntax to access nested values in objects, I'm trying to use es6 Map object, which has a convenient map.get() method. I'm trying to avoid having to do the following with normal Javascript objects.

// access deeply nested values...
obj['k1'] &&
obj['k1']['k2'] &&
obj['k1']['k2']['k3']

Am I building the map wrong? only map.get('k1') works (can't get nested map values, just the whole thing under k1: is given as a value).

var obj = {'k1': {'k2': {'k3': 'Test Value'}}};
const map = new Map(Object.entries(obj));

console.log(map.get('k1')); 
console.log(map.get('k2')); 
console.log(map.get('k3')); 
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Gallaxhar
  • 976
  • 1
  • 15
  • 28
  • You're only mapping one key, `k1`, in the new map. A map by itself won't solve your problem; you still need to traverse the structure to drill down. – Mark Jun 27 '18 at 17:38
  • Your other keys are nested inside the value of `k1`, `Object.entries(obj)` will give only one key/value pair, so the resulting map will also only have that one. – ASDFGerte Jun 27 '18 at 17:38
  • You could always extend Map to implement a multi-level `get` so you could do something like `.getml('k1.k2.k3')` ... but internally it's going to have to access each level in turn similarly to what you're trying to avoid. A better question might be: If you're not using those top levels of your data structure, why do you have them? – Tibrogargan Jun 27 '18 at 17:42
  • You seem to be looking for [easier syntax to access potentially non-existant nested properties](https://stackoverflow.com/questions/2631001/javascript-test-for-existence-of-nested-object-key), not for a `Map`. – Bergi Mar 22 '19 at 19:04

4 Answers4

2

You need to iterate all keys and the nested objects as well.

function add(object, map) {
    Object.entries(object).forEach(([k, v]) => {
        map.set(k, v);
        if (v && typeof v === 'object') {
            add(v, map);
        }
    });
}

var obj = { k1: { k2: { k3: 'Test Value' } } };
const map = new Map;

add(obj, map);

console.log(map.get('k1')); 
console.log(map.get('k2')); 
console.log(map.get('k3')); 
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
2

Your question about querying a nested object using Map is invalid. Map cannot do this. You either have to flatten your object prior to putting it into Map or find an alternative way that supports querying nested data.

I would advise against flattening your structure for the sole purpose of using Map. How do you handle key collisions? It becomes more complex.

So let's look at some ways to query nested data:

// how to query a nested data structure.

const get = (prop, ...props) => obj =>
  obj == null || prop == null
    ? obj
    : get(...props)(obj[prop])

const obj = {'k1': {'k2': {'k3': 'Test Value'}}};
const result = get('k1', 'k2', 'k3')(obj) // => 'Test Value'

You can also use a library like Ramda.

import path from 'ramda/src/path

const obj = {'k1': {'k2': {'k3': 'Test Value'}}};
const result = path(['k1', 'k2', 'k3'], obj)  // => 'Test Value'
joelnet
  • 13,621
  • 5
  • 35
  • 49
0

You can try es6 destructuring 101.

let obj = {'k1': {'k2': {'k3': 'Test Value'}}};

let {k1} = obj;
let {k1: {k2}} = obj;
let {k1: {k2: {k3}}} = obj;

console.log(k1);
console.log(k2);
console.log(k3)

I hope this will help.

Youssef BH
  • 534
  • 5
  • 14
0

I'm doing something like this to create graphs/trees right now. This isn't exactly what I'm doing but it should give you the idea.

In es5 I would say

let root = {
  1:  {
       a: 'hi from a'
       b: ...
       }  
  2:  {...}
}

root[1][a]; //returns 'hi from a'
root['getme']['abeer']; //Type Error 

using Map:

  let root = new Map();
  root.set(1, new Map());
  root.get(1).set('a', 'hi from a');

  root.get(1).get('a');  //returns 'hi from a'

  root.get(1).get('me a beer');  //undefined  

  root.get('me').get('a-beer'); 
  //Uncaught TypeError: Cannot read property 'get' of undefined

DanG
  • 91
  • 1
  • 9