Select a nested value from the object in javascript
Rajnish Katharotiya
Posted on May 1, 2020
Selecting a nested value from an object is a common thing for any javascript application, and when you do deep nesting selection like (user.profile.address.city) it's risky and increases chances of throwing an exception if any one node is undefined which will terminate your process and break page with a white screen. So, what you'd for a solution? ( 🤠 please leave it in comment box ).
Before going further, I would like to welcome you to a new episode of series call Javascript Useful Snippets. In this series, I'm sharing some shortcodes and useful functions that can let you make your code faster and neat. So, if you haven't read my previous episodes articles please check it out here or else stay tuned till the end to learn something new 😋 .
Well, there are various ways to prevent exceptions, let me write some of popular once here:-
user && user.profile && user.profile.address && user.profile.address.
user?.profile?.address?.city
Maybe to deal with it, the most common way is the first one. But recently a new operator introduced to handle it in a better way is called operational Channing operator (?. - you can read it more on here ) So, this two can make it little easier to handle nesting selection. But I think I found one much better function to handle it. ( excited? 😀 - stay tuned if yes )
get(), this function has two types of argument one is an object of records, and the rest are strings (like this "profile.address.city") to selection from an object. So, in return, you will receive a collection of selected values.
How does this get() works?
const get = (obj, ...selectors) =>
[...selectors].map(s =>
s
.replace(/\[([^\[\]]*)\]/g, '.$1.')
.split('.')
.filter(t => t !== '')
.reduce((prev, cur) => prev && prev[cur], obj)
);
As mentioned above, the first argument will be the object and rest argument I've stored into selectors
with the use of spreading operator ( it's a concept to clone object/array - find out in more detail from here ) and stored it into an array. And in return of this function, I've used a map method to select the individual record and with that first, I've replaced regex match string with spinal tap case operator ( please find a detailed explanation from here ) then second used split method to divide sting from "." which will return an array of strings, so in the third step filtered all empty record form collection and in the last step, by using reduce method I'm selecting values from value until I reach to the last location. And using a double end operator (&&) to prevent exception like if I don't any result from the second step then it'll make it undefined
from there and stop looking for further node.
How to use get() ?
const obj = {
profile : { user : { name: "xyz", surname: "abc" }},
relations: [ { name: 'one' }, { name: 'two' } ]
};
get(obj, 'profile.user.name', 'relations[0]', 'relations[2].name');
// ['xyz', { name: 'one' }, undefined]
So, as you see 2-4 arguments are differents selctors i've used here while 4th selector expect name from second indexed data of relations (relations[2]) whereas relation collection doesn't have second index at all with data so in result get function stop selection of name and just throw undefined without error.
I found this function very useful while selecting from deep nested object especially with uncertain nodes in the object. So, I thought to share it with you too. I hope you liked my explanation (if yes, hit like ❤️ button ) and if you found it informative then do follow from here because I'll learn and share every day.😋
Also follow/subscribe me on my social media account to connect with me : twitter, youtube
Posted on May 1, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.