2

Suppose I got an object defined as such:

const me = {
    id: 1,
    name: 'James',
    age: 40,
    family: {
        mother: {
            id: 101,
            name: 'Bea',
            age: 66
        },
        father: {
            id: 102,
            name: 'Martin',
            age: 69
        },
        children: [
            {
                id: 11,
                name: 'Tom',
                age: 18,
            },
            {
                id: 12,
                name: 'Nancy',
                age: 13,
            },
        ],
    },
}

How does one easily access a value by just giving an array of strings of the chained properties' names? For example, calling:

search(me, ['family', 'father', 'age'])

which would be the same as:

me['family']['father']['age']

would return 69.

PS: What about having search(me, ['family', 'children', 'name']) return ['Tom', 'Nancy']?

PSS: Or even search(me, ['family', 'children', ['name', 'age']]) returning

[
    {
        name: 'Tom',
        age: 18
    },
    {
        name: 'Nancy',
        age: 13
    }
]

EDIT: I went checking out lodash/deepdash libraries, but couldn't really figure it out by myself.

4
  • Have a look at Accessing nested JavaScript objects and arrays by string path except that in your case you have already have the array (no need to split the path). Commented Apr 7, 2021 at 18:35
  • What have you tried so far? Have you tried writing an utility function for this, or something? Commented Apr 7, 2021 at 18:36
  • FYI, this is not Java, so this: {'family', 'father', 'age'} is not an array. Commented Apr 7, 2021 at 18:36
  • You should ask one question at a time, I've answered the first one but your PS and PSS are separate questions Commented Apr 7, 2021 at 18:43

3 Answers 3

3

You can do that with this simple recursive function which takes an array as the query:

const me = {
    id: 1,
    name: 'James',
    age: 40,
    family: {
        mother: {
            id: 101,
            name: 'Bea',
            age: 66
        },
        father: {
            id: 102,
            name: 'Martin',
            age: 69
        },
        children: [
            {
                id: 11,
                name: 'Tom',
                age: 18,
            },
            {
                id: 12,
                name: 'Nancy',
                age: 13,
            },
        ],
    },
}


function search(obj, [first, ...rest]) {
  return rest.length ? search(obj[first], rest) : obj[first];
}

const result = search(me, ['family', 'father', 'age']);

console.log(result);

Sign up to request clarification or add additional context in comments.

3 Comments

Or even an ES6 one-liner : const search = (obj, [first, ...rest]) => rest.length ? search(obj[first], rest) : obj[first]
Yes even that 😉
Yea, I was attempting something like that with the array parameters, but I hadn't gotten it to work... Thanks!
0

Though it's bit lengthy, you could try this for all your combinations.

const me={id:1,name:'James',age:40,family:{mother:{id:101,name:'Bea',age:66},father:{id:102,name:'Martin',age:69},children:[{id:11,name:'Tom',age:18,},{id:12,name:'Nancy',age:13,},],},}

function search(data, searchPattern) {
    const keys = [...searchPattern];
    
    //picking last key and it's corresponding value
    const lastKey = keys.pop();
    const resultInst = keys.reduce((acc,key)=>{
        return acc[key];
    }, data);
    
    // if it's array iterating it further to construct the response
    if (Array.isArray(resultInst)) {
        return resultInst.map(inst => {
            if (Array.isArray(lastKey)) {
                return lastKey.reduce((accInner,key) => {
                    accInner[key] = inst[key];
                    return accInner;
                }, {});
            } else {
                return inst[lastKey];
            }
        });
    } else {
        // else just returning property's value
        return resultInst[lastKey];
    }
}

console.log(search(me, ['family', 'father', 'age']))
console.log(search(me, ['family', 'children', 'name']))
console.log(search(me, ['family', 'children', ['name', 'age']]))

Comments

0

Some interesting requirements you have there! Here is an all-in-one answer using object-scan and lodash

.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>
<script type="module">
import objectScan from 'https://cdn.jsdelivr.net/npm/[email protected]/lib/index.min.js';

const myData = { id: 1, name: 'James', age: 40, family: { mother: { id: 101, name: 'Bea', age: 66 }, father: { id: 102, name: 'Martin', age: 69 }, children: [{ id: 11, name: 'Tom', age: 18 }, { id: 12, name: 'Nancy', age: 13 }] } };

const search = (data, needle) => objectScan([needle], {
  reverse: false,
  rtn: ['key', 'value'],
  useArraySelector: false,
  afterFn: (state) => {
    if (state.result.length === 0) {
      state.result = undefined;
    } else if (needle.includes('{')) {
      const prefixLength = lodash
        .zip(...state.result.map(([k]) => k))
        .findIndex((e) => new Set(e).size > 1);
      const result = [];
      state.result.forEach(([k, v]) => lodash.set(result, k.slice(prefixLength), v));
      state.result = result;
    } else if (
      state.result.length === 1
      && state.result.every(([k]) => k.every((p) => typeof p === 'string'))
    ) {
      state.result = state.result[0][1];
    } else {
      state.result = state.result.map(([k, v]) => v);
    }
  }
})(data);

console.log(search(myData, 'family.father.age'));
// => 69

console.log(search(myData, 'family.children.name'));
// => [ 'Tom', 'Nancy' ]

console.log(search(myData, 'family.children.{age,name}'));
// => [ { name: 'Tom', age: 18 }, { name: 'Nancy', age: 13 } ]

console.log(search(myData, 'family.father.unknown'));
// => undefined
</script>

Disclaimer: I'm the author of object-scan

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.