Lets say my object looks like the below. Its a mix of different arrays and parents, no hierarchical order. e.g.
\"person\": {
\"id\": 12345,
\"name\": \"John Doe
I generalized it a bit with code shamelessly stolen from my own lib: goodcore
I chose a recursice approach since I believe the code is much easier to analyze although it has more code.
let obj = {
"id": 12345,
"name": "John Doe",
"emergencyContacts": [{
"name": "Jane Doe",
"phone": "888-555-1212",
"relationship": "spouse",
"moreDetails": {
"id": 12345,
"phones": {},
"home": "800-123-4567",
"mobile": "877-123-1234"
}
},
{
"name": "Justin Doe",
"phone": "877-123-1212",
"relationship": "parent",
"mobile": "877-123-1234"
}
],
"workContacts": [{
"name": "Jane Doe",
"phone": "888-555-1212",
"relationship": "spouse",
"moreworkDetails": {
"id": 12345,
"phones": {},
"home": "800-123-4567",
"mobile": "877-123-1236"
}
},
{
"name": "Justin Doe",
"phone": "877-123-1212",
"relationship": "parent",
"mobile": "877-123-1235"
}
]
};
function isObject(it) {
return it !== null && typeof it === "object";
}
function isArray(it) {
return Array.isArray ? Array.isArray(it) : Object.prototype.toString.call(it) === "[object Array]";
}
function forEach(target, fn) {
if(isArray(target)) {
target.forEach(fn);
} else {
Object.entries(target).forEach(([key, value]) => fn(value, key));
}
}
function objReduce(obj, fn, acc) {
let a = acc;
forEach(obj, (value, key) => {
if(isObject(value) || isArray(value)) {
a = objReduce(value, fn, a);
}
a = fn(a, value, key);
});
return a;
}
objReduce(obj, (acc, cur, key) => {
if(key === "mobile") {
acc.push(cur);
}
return acc;
}, []);
Basically what it does is that it creats an object reduce function that loops over all properties and runs an accumulator function on it much like Array.prototype.reduce does for arrays. It needed a bit of code since it handles arrays and objects arbitrarily.
You will need a recursive function. For explanation please check the comments
let person = {
"id": 12345,
"name": "John Doe",
"emergencyContacts": [{
"name": "Jane Doe",
"phone": "888-555-1212",
"relationship": "spouse",
"moreDetails": {
"id": 12345,
"phones": {},
"home": "800-123-4567",
"mobile": "877-123-1234"
}
},
{
"name": "Justin Doe",
"phone": "877-123-1212",
"relationship": "parent",
"mobile": "877-123-1234"
}
],
"workContacts": [{
"name": "Jane Doe",
"phone": "888-555-1212",
"relationship": "spouse",
"moreworkDetails": {
"id": 12345,
"phones": {},
"home": "800-123-4567",
"mobile": "877-123-1236"
}
},
{
"name": "Justin Doe",
"phone": "877-123-1212",
"relationship": "parent",
"mobile": "877-123-1235"
}
]
}
let arrys = [];
//iterate the object
function recursive(obj, key) {
//iterate the object
for (let keys in obj) {
// check if the key name is same as the desired one
if (keys === key) {
// then push the value to an array
arrys.push(obj[keys])
} else {
// if the value of a key is an array & if it is not empty
if (Array.isArray(obj[keys]) && obj[keys].length > 0) {
// iterate the array. in each iteration you will get the object
// example emergencyContacts. In each iteration
// call the same function with new data
obj[keys].forEach(function(item) {
// pass that object to the same function
recursive(item, key)
})
}
// if the value is an object then again call the same function
else if (typeof obj[keys] === 'object') {
recursive(obj[keys], key)
}
}
}
}
recursive(person, 'mobile');
//create object from the array
let newObj = {}
for (let m = 0; m < arrys.length; m++) {
newObj[m] = arrys[m]
}
console.log(newObj)
You don't need recursion. You can do it with while
loop:
function searchFor(what, where) {
const stack = [where];
const result = [];
while (stack.length) {
const item = stack.pop();
if (Array.isArray(item)) {
item.forEach(el => stack.push(el));
continue;
}
if (item && typeof item === "object")
Object.entries(item).forEach(([key, value]) =>
key === what ?
result.push(value) :
stack.push(value)
)
}
return result;
}
returnValuesForAttribute = (attr) => {
let mobile = {};
let index = 0;
Object.values(person).map(first_level => {
if (Array.isArray(first_level)) {
first_level.map(el => {
if (Object.keys(el).includes(attr)) {
mobile[index] = el[attr];
index++;
}
Object.values(el).map(second_level => {
if (typeof second_level === 'object' && second_level[attr]) {
mobile[index] = second_level[attr];
index++;
}
})
})
}
});
return mobile;
}
returnValuesForAttribute('mobile');
Output: {0: "877-123-1234", 1: "877-123-1234", 2: "877-123-1234", 3: "877-123-1234"}