How to get all keys with values from nested objects
You can use for...in
and create recursive function.
var obj = {"check_id":12345,"check_name":"Name of HTTP check","check_type":"HTTP","tags":["example_tag"],"check_params":{"basic_auth":false,"params":["size",{"a":"b"}],"encryption":{"enabled":true}}}
var keys = []
function getKeys(data, k = '') {
for (var i in data) {
var rest = k.length ? '.' + i : i
if (typeof data[i] == 'object') {
if (!Array.isArray(data[i])) {
getKeys(data[i], k + rest)
}
} else keys.push(k + rest)
}
}
getKeys(obj)
console.log(keys)
You could check the keys and iterate otherwise push the path to the result set.
function getKeys(object) {
function iter(o, p) {
if (Array.isArray(o)) { return; }
if (o && typeof o === 'object') {
var keys = Object.keys(o);
if (keys.length) {
keys.forEach(function (k) { iter(o[k], p.concat(k)); });
}
return;
}
result.push(p.join('.'));
}
var result = [];
iter(object, []);
return result;
}
var object = { check_id: 12345, check_name: "Name of HTTP check", check_type: "HTTP", tags: ["example_tag"], check_params: { basic_auth: false, params: ["size"], encryption: { enabled: true } } };
console.log(getKeys(object));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use reduce like this:
const keyify = (obj, prefix = '') =>
Object.keys(obj).reduce((res, el) => {
if( Array.isArray(obj[el]) ) {
return res;
} else if( typeof obj[el] === 'object' && obj[el] !== null ) {
return [...res, ...keyify(obj[el], prefix + el + '.')];
}
return [...res, prefix + el];
}, []);
const input = {
"check_id":12345,
"check_name":"Name of HTTP check",
"check_type":"HTTP",
"tags":[
"example_tag"
],
"check_params":{
"basic_auth":false,
"params":[
"size"
],
"encryption": {
"enabled": true,
"testNull": null,
}
}
};
const output = keyify(input);
console.log(output);
Edit1: For the general case where you want to include arrays.
const keyify = (obj, prefix = '') =>
Object.keys(obj).reduce((res, el) => {
if( typeof obj[el] === 'object' && obj[el] !== null ) {
return [...res, ...keyify(obj[el], prefix + el + '.')];
}
return [...res, prefix + el];
}, []);
const input = {
"check_id":12345,
"check_name":"Name of HTTP check",
"check_type":"HTTP",
"tags":[
"example_tag"
],
"nested": [
{ "foo": 0 },
{ "bar": 1 }
],
"check_params":{
"basic_auth":false,
"params":[
"size"
],
"encryption": {
"enabled": true,
"testNull": null,
}
}
};
const output = keyify(input);
console.log(output);
A generator makes quick work of this kind of problem -
function* deepKeys (t, pre = [])
{ if (Array.isArray(t))
return
else if (Object(t) === t)
for (const [k, v] of Object.entries(t))
yield* deepKeys(v, [...pre, k])
else
yield pre.join(".")
}
const input =
{check_id:12345,check_name:"Name of HTTP check",check_type:"HTTP",tags:["example_tag"],check_params:{basic_auth:false,params:["size"],encryption:{enabled:true,testNull:null,}}}
console.log(Array.from(deepKeys(input)))
[ "check_id"
, "check_name"
, "check_type"
, "check_params.basic_auth"
, "check_params.encryption.enabled"
, "check_params.encryption.testNull"
]
Or a pure functional expression which eagerly computes all keys -
const deepKeys = (t, pre = []) =>
Array.isArray(t)
? []
: Object(t) === t
? Object
.entries(t)
.flatMap(([k, v]) => deepKeys(v, [...pre, k]))
: pre.join(".")
const input =
{check_id:12345,check_name:"Name of HTTP check",check_type:"HTTP",tags:["example_tag"],check_params:{basic_auth:false,params:["size"],encryption:{enabled:true,testNull:null,}}}
console.log(deepKeys(input))
[ "check_id"
, "check_name"
, "check_type"
, "check_params.basic_auth"
, "check_params.encryption.enabled"
, "check_params.encryption.testNull"
]