I am working on a problem where I would like to transform the following object structure:
[
{
"label": "testType",
"categories": [
{
"label": "testCatType",
"subCategories": [
{
"label": "newSubCat",
"subSubCategories": [
{
"label": "newSubSubCat1"
},
{
"label": "newSubSubCat2"
},
{
"label": "newSubSubCat3"
}
]
}
]
}
]
},
{
"label": "newType",
"categories": [
{
"label": "newCat10",
"subCategories": [
{
"label": "newCatSub1",
"subSubCategories": [
{
"label": "bingo11"
},
{
"label": "bingo12"
},
{
"label": "bingo15"
}
]
}
]
}
]
},
{
"label": "displacement",
"categories": []
},
{
"label": "brush",
"categories": [
{
"label": "blood",
"subCategories": []
},
{
"label": "damage",
"subCategories": []
},
]
}
]
into something like this:
{
"testType": {
"testCatType": {
"newSubCat": {
"newSubSubCat1": {},
"newSubSubCat2": {},
"newSubSubCat3": {}
}
}
},
"newType": {
"newCat10": {
"newCatSub1": {
"bingo11": {},
"bingo12": {},
"bingo15": {}
}
}
},
"displacement": {},
....
}
I have implemented the following recursive solution for this:
recursiveAssign(obj, json) {
if (_.isUndefined(obj)) {
return;
}
let totalKeys = _.keys(obj);
return _.assign(json, { [obj['label']]: this.test(obj[totalKeys[1]], json) })
}
transform(typeObj){
let json = {};
_.forEach(typeObj, obj => {
let totalKeys = _.keys(obj);
if (totalKeys < 2) {
_.assign(json, obj['label']);
} else {
_.assign(json, { [obj['label']]: this.recursiveAssign(obj[totalKeys[1]], json) })
}
})
}
Now the end result of this is an object that is a copy of itself on each level and I don't quite understand what the problem is. I think my approach is not faulty as I take the label and call the recursive function on the other part of that object. Can please someone point out to the potential issue!
You can write transform as a simple recursive function -
function transform (all = []) {
return Object.fromEntries(all.map(t =>
[t.label, transform(t.categories ?? t.subCategories ?? t.subSubCategories)]
))
}
const data =
[{"label":"testType","categories":[{"label":"testCatType","subCategories":[{"label":"newSubCat","subSubCategories":[{"label":"newSubSubCat1"},{"label":"newSubSubCat2"},{"label":"newSubSubCat3"}]}]}]},{"label":"newType","categories":[{"label":"newCat10","subCategories":[{"label":"newCatSub1","subSubCategories":[{"label":"bingo11"},{"label":"bingo12"},{"label":"bingo15"}]}]}]},{"label":"displacement","categories":[]},{"label":"brush","categories":[{"label":"blood","subCategories":[]},{"label":"damage","subCategories":[]},]}]
console.log(JSON.stringify(transform(data), null, 2))
{
"testType": {
"testCatType": {
"newSubCat": {
"newSubSubCat1": {},
"newSubSubCat2": {},
"newSubSubCat3": {}
}
}
},
"newType": {
"newCat10": {
"newCatSub1": {
"bingo11": {},
"bingo12": {},
"bingo15": {}
}
}
},
"displacement": {},
"brush": {
"blood": {},
"damage": {}
}
}
You can chain ... ?? t.subSubSubCategories and ... ?? t.subSubSubSubCategories, if needed. A better approach would be to create a consistent node interface for all nodes in your graph. You could achieve this by renaming all sub*Categories to simply categories. This will give each node an inteface like
Node: { label: String, categories: Array<Node> }
You can solve this in pure js like this:
const arr = [{ "label": "testType", "categories": [{ "label": "testCatType", "subCategories": [{ "label": "newSubCat", "subSubCategories": [{ "label": "newSubSubCat1" }, { "label": "newSubSubCat2" }, { "label": "newSubSubCat3" }] }] }] }, { "label": "newType", "categories": [{ "label": "newCat10", "subCategories": [{ "label": "newCatSub1", "subSubCategories": [{ "label": "bingo11" }, { "label": "bingo12" }, { "label": "bingo15" }] }] }] }, { "label": "displacement", "categories": [] }, { "label": "brush", "categories": [{ "label": "blood", "subCategories": [] }, { "label": "damage", "subCategories": [] }, ] }];
let result = recursive(arr);
console.log(result);
function recursive(arr) {
let result = {};
let returnValue = {}
for (let obj of arr) {
let entries = Object.entries(obj);
if (!entries.length) {
return {};
}
for (let [key, value] of entries) {
if (typeof value == "object") {
result = recursive(value);
}
}
const label = obj["label"];
returnValue = { ...returnValue,
[obj["label"]]: result
};
}
return returnValue;
}
.as-console-wrapper {min-height: 100%;}
Related
I have a nested array like below. There are about 100 de objects in the array. The de objects also have deg[0] array but most likely I will only have the first index. Now the trick is that the de are subset of deg. Which means each deg can have say 10 de. How can I retrieve the deg and there associated de and map it into a new array like:
newArray = [
deg1: [
{de1},
{de2}
],
deg2: [
{de1},
{de2}
]
]
Here is my nested array. I posted four but the list is over a 100.
{
"name": "Report",
"id": "2YYUEZ6I1r9",
"dse1": [
{
"de1": {
"name": "Number",
"id": "HjMOngg3kuy",
"de1-av": [
{
"value": "FHaQMPv9zc7",
"attribute": {
"id": "uwVkIP7PZDt"
}
},
{
"value": "something",
"attribute": {
"id": "FHaQMPv9zc7"
}
}
],
"deg1": [
{
"name": "TB",
"id": "2XJB1JO9qX8"
}
]
}
},
{
"de2": {
"name": "Number of",
"id": "a3dtGETTawy",
"de2-av": [
{
"value": "FHaQMPv9zc7",
"attribute": {
"id": "uwVkIP7PZDt"
}
},
{
"value": "something",
"attribute": {
"id": "FHaQMPv9zc7"
}
}
],
"deg1": [
{
"name": "Secondary",
"id": "w99RWzXHgtw"
}
]
}
},
{
"de1": {
"name": "Number of",
"id": "a3dtGETTawy",
"de1av": [
{
"value": "FHaQMPv9zc7",
"attribute": {
"id": "uwVkIP7PZDt"
}
},
{
"value": "something",
"attribute": {
"id": "FHaQMPv9zc7"
}
}
],
"deg2": [
{
"name": "Secondary",
"id": "w99RWzXHgtw"
}
]
}
},
{
"de2": {
"name": "Number of",
"id": "a3dtGETTawy",
"de2av": [
{
"value": "FHaQMPv9zc7",
"attribute": {
"id": "uwVkIP7PZDt"
}
},
{
"value": "something",
"attribute": {
"id": "FHaQMPv9zc7"
}
}
],
"deg2": [
{
"name": "Tertiary",
"id": "w99RWzXHgtw"
}
]
}
}
]
}
Group array of objects by property (this time a property to be matched by a reg exp) using Array.reduce.
Update: Ignoring missing keys.
var input={name:"Report",id:"2YYUEZ6I1r9",dse1:[{de1:{name:"Number",id:"HjMOngg3kuy","de1-av":[{value:"FHaQMPv9zc7",attribute:{id:"uwVkIP7PZDt"}},{value:"something",attribute:{id:"FHaQMPv9zc7"}}],deg1:[{name:"TB",id:"2XJB1JO9qX8"}]}},{de2:{name:"Number of",id:"a3dtGETTawy","de2-av":[{value:"FHaQMPv9zc7",attribute:{id:"uwVkIP7PZDt"}},{value:"something",attribute:{id:"FHaQMPv9zc7"}}],deg1:[{name:"Secondary",id:"w99RWzXHgtw"}]}},{de1:{name:"Number of",id:"a3dtGETTawy",de1av:[{value:"FHaQMPv9zc7",attribute:{id:"uwVkIP7PZDt"}},{value:"something",attribute:{id:"FHaQMPv9zc7"}}],deg2:[{name:"Secondary",id:"w99RWzXHgtw"}]}},{de2:{name:"Number of",id:"a3dtGETTawy",de2av:[{value:"FHaQMPv9zc7",attribute:{id:"uwVkIP7PZDt"}},{value:"something",attribute:{id:"FHaQMPv9zc7"}}],deg2:[{name:"Tertiary",id:"w99RWzXHgtw"}]}}]}
var reg = new RegExp("^de[0-9]+$");
var reg2 = new RegExp("^deg[0-9]+$");
let obj = input['dse1'].reduce(function(agg, item) {
// do your group by logic below this line
var key = Object.keys(item).find(function(key) {
return key.match(reg) ? key : null;
})
if (key) {
var key2 = Object.keys(item[key]).find(function(key) {
return key.match(reg2) ? key : null;
})
agg[key] = agg[key] || [];
if (key2) {
var to_push = {}
to_push[key2] = item[key][key2]
agg[key].push(to_push)
}
}
// do your group by logic above this line
return agg
}, {});
console.log(obj)
.as-console-wrapper {
max-height: 100% !important;
}
I have this object below
{
"root": {
"data": {
"page": 1,
"contents": [
{
"node": {
"id": "UzpfSTE",
"stats": {
"viewers": {
"nodes": [
{
"id": "1",
"name": "John"
},
{
"id": "2",
"name": "Shaun"
}
]
}
}
}
},
{
"node": {
"id": "UzpfSTG",
"stats": {
"viewers": {
"nodes": [
{
"id": "3",
"name": "Liam"
}
]
}
}
}
}
]
}
}
}
There is contents node, each of them will have many viewers, all I want is to extract all viewers name to an array, in this instance my result will be [John, Shaun, Liam]
I have this approach:
const data = JSON.parse(rt)
const contents = data.root.data.contents
const newArray = []
for (i = 0; i < contents.length; i++) {
arr2 = contents[i].node.stats.viewers.nodes
for (n = 0; n < arr2.length; n++) {
name = arr2[n].name
newArray.push(name)
}
}
console.log(newArray)
>>> [John, Shaun, Liam]
Which does the job, but occasionaly the object key names change and I have to alter everytime.
So is there more elegant way to do this?
You can simplify that imperative logic like this.
I don't understand what you mean by "the object key names change" though
const data = {
"root": {
"data": {
"page": 1,
"contents": [{
"node": {
"id": "UzpfSTE",
"stats": {
"viewers": {
"nodes": [{
"id": "1",
"name": "John"
},
{
"id": "2",
"name": "Shaun"
}
]
}
}
}
},
{
"node": {
"id": "UzpfSTG",
"stats": {
"viewers": {
"nodes": [{
"id": "3",
"name": "Liam"
}]
}
}
}
}
]
}
}
}
const names = data.root.data.contents.flatMap(({
node: {
stats: {
viewers: {
nodes
}
}
}
}) => nodes.map(({
name
}) => name))
console.log(names)
const data = JSON.parse(rt)
const contents = data.root.data.contents
const viewers = contents.map(item => item.node.stats.viewers.nodes).flat()
const viewerNames = viewers.map(viewer => viewer.name)
What is the cleanest way to find object and return that based on id , If I don't know how many nested object there will be in my object ?
Let's say I have the following structure :
myObj = {
"id": "5e6b8961ba08180001a10bb6",
"children": [
{
"id": "5e6b8961ba08180001a10bb7",
"refrenceId": "SEC-02986",
"children": [
{
"id": "5e58d7bc1bbc71000118c0dc"
},
{
"id": "5e58d7bc1bbc71000118c0dd",
"refrenceId": "SKU-00343"
},
{
"id": "5e590d571bbc71000118c102",
"refrenceId": "SKU-05290"
},
{
"id": "5e590df71bbc71000118c109",
"children": [
{
"id": "5e590df71bbc71000118c10a"
},
{
"id": "5e590df71bbc71000118c10b",
"refrenceId": "SKU-00444"
},
{
"id": "5e5cb9428ae591000177c0f6"
}
]
},
{
"id": "5e81899f0bab450001dcfc1d",
"refrenceId": "SEC-03260"
},
{
"id": "5e81c4b51503860001f97f6c",
"refrenceId": "SEC-03267",
"children": [
{
"id": "5e8ad5175d374200014edb3a",
"refrenceId": "SEC-03409",
"children": [
{
"id": "5e8f28882d94c1000156bebe"
}
]
},
{
"id": "5e8ad5175d374200014edb3c",
"refrenceId": "SEC-03410"
},
{
"id": "5e8f29082d94c1000156bec6",
"refrenceId": "SEC-03495"
}
]
}
]
}
Suppose, I want to find the one with id "5e590df71bbc71000118c10b", and return that object from nested object.
I have tried using following code:
function nodeHasChildren(children, id) {
for (const child of children) {
if (child.id === id) {
if (Array.isArray(child.children) && child.children.length > 0) {
return child;
}
}
else {
const result = nodeHasChildren(child.children, id);
if (result !== undefined) {
return result
}
}
}
}
console.log(nodeWithIdHasChildren(myObj, "5e590df71bbc71000118c10b"));
Use simple recursion
function findDeepById(node, id) {
if (node.id === id) return node;
if (node.children) {
for(const child of node.children){
const match = findDeepById(child, id);
if (match) return match;
}
}
}
const myObj = {
"id": "5e6b8961ba08180001a10bb6",
"children": [{
"id": "5e6b8961ba08180001a10bb7",
"refrenceId": "SEC-02986",
"children": [{
"id": "5e58d7bc1bbc71000118c0dc"
},
{
"id": "5e58d7bc1bbc71000118c0dd",
"refrenceId": "SKU-00343"
},
{
"id": "5e590d571bbc71000118c102",
"refrenceId": "SKU-05290"
},
{
"id": "5e590df71bbc71000118c109",
"children": [{
"id": "5e590df71bbc71000118c10a"
},
{
"id": "5e590df71bbc71000118c10b",
"refrenceId": "SKU-00444"
},
{
"id": "5e5cb9428ae591000177c0f6"
}
]
},
{
"id": "5e81899f0bab450001dcfc1d",
"refrenceId": "SEC-03260"
},
{
"id": "5e81c4b51503860001f97f6c",
"refrenceId": "SEC-03267",
"children": [{
"id": "5e8ad5175d374200014edb3a",
"refrenceId": "SEC-03409",
"children": [{
"id": "5e8f28882d94c1000156bebe"
}]
},
{
"id": "5e8ad5175d374200014edb3c",
"refrenceId": "SEC-03410"
},
{
"id": "5e8f29082d94c1000156bec6",
"refrenceId": "SEC-03495"
}
]
}
]
}]
};
function findDeepById(node, id) {
if (node.id === id) return node;
if (node.children) {
for(const child of node.children){
const match = findDeepById(child, id);
if (match) return match;
}
}
}
console.log(findDeepById(myObj, "5e590df71bbc71000118c10b"));
In short, this part was the biggest problem:
if (child.id === id) {
if (Array.isArray(child.children) && child.children.length > 0) {
return child;
}
}
You've found your object, why look for its children?
ORIGINAL ANSWER/WORKING SOLUTION
For start, you need to make your original object iterable because that's what your function expects, I've done so by simply making it an array like nodeHasChildren([myObj], ... when calling the function. Then, after some cleanup and fixing the logic mentioned above, we get this (added relevant comments to the code below):
myObj = {
"id": "5e6b8961ba08180001a10bb6",
"children": [{
"id": "5e6b8961ba08180001a10bb7",
"refrenceId": "SEC-02986",
"children": [{
"id": "5e58d7bc1bbc71000118c0dc"
},
{
"id": "5e58d7bc1bbc71000118c0dd",
"refrenceId": "SKU-00343"
},
{
"id": "5e590d571bbc71000118c102",
"refrenceId": "SKU-05290"
},
{
"id": "5e590df71bbc71000118c109",
"children": [{
"id": "5e590df71bbc71000118c10a"
},
{
"id": "5e590df71bbc71000118c10b",
"refrenceId": "SKU-00444"
},
{
"id": "5e5cb9428ae591000177c0f6"
}
]
},
{
"id": "5e81899f0bab450001dcfc1d",
"refrenceId": "SEC-03260"
},
{
"id": "5e81c4b51503860001f97f6c",
"refrenceId": "SEC-03267",
"children": [{
"id": "5e8ad5175d374200014edb3a",
"refrenceId": "SEC-03409",
"children": [{
"id": "5e8f28882d94c1000156bebe"
}]
},
{
"id": "5e8ad5175d374200014edb3c",
"refrenceId": "SEC-03410"
},
{
"id": "5e8f29082d94c1000156bec6",
"refrenceId": "SEC-03495"
}
]
}
]
}]
}
function nodeHasChildren(children, id) {
for (const child of children) {
if (child.id === id) {
// solution found, no need to do anything else
console.log("SOLUTION: ");
return child;
} else {
// check if it has children and iterate over them recursively
if (Array.isArray(child.children) && child.children.length > 0)
var result = nodeHasChildren(child.children, id);
// check if the result was found in children in the line above
if (result != undefined)
return result;
}
}
}
console.log(nodeHasChildren([myObj], "5e590df71bbc71000118c10b"));
console.log(nodeHasChildren([myObj], "5e8ad5175d374200014edb3c"));
We now use object-scan for simple data processing tasks. It's pretty awesome once you wrap your head around it. Here is how you could answer your questions
// const objectScan = require('object-scan');
const find = (id, input) => objectScan(['**'], {
rtn: 'value',
abort: true,
filterFn: ({ value }) => value.id === id
})(input);
const myObj = { id: '5e6b8961ba08180001a10bb6', children: [{ id: '5e6b8961ba08180001a10bb7', refrenceId: 'SEC-02986', children: [{ id: '5e58d7bc1bbc71000118c0dc' }, { id: '5e58d7bc1bbc71000118c0dd', refrenceId: 'SKU-00343' }, { id: '5e590d571bbc71000118c102', refrenceId: 'SKU-05290' }, { id: '5e590df71bbc71000118c109', children: [{ id: '5e590df71bbc71000118c10a' }, { id: '5e590df71bbc71000118c10b', refrenceId: 'SKU-00444' }, { id: '5e5cb9428ae591000177c0f6' }] }, { id: '5e81899f0bab450001dcfc1d', refrenceId: 'SEC-03260' }, { id: '5e81c4b51503860001f97f6c', refrenceId: 'SEC-03267', children: [{ id: '5e8ad5175d374200014edb3a', refrenceId: 'SEC-03409', children: [{ id: '5e8f28882d94c1000156bebe' }] }, { id: '5e8ad5175d374200014edb3c', refrenceId: 'SEC-03410' }, { id: '5e8f29082d94c1000156bec6', refrenceId: 'SEC-03495' }] }] }] };
console.log(find('5e8ad5175d374200014edb3a', myObj));
/* =>
{ id: '5e8ad5175d374200014edb3a',
refrenceId: 'SEC-03409',
children: [ { id: '5e8f28882d94c1000156bebe' } ] }
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan
I'm trying to transform this JSON into array so that I can simply list them as key-value pairs in html. The JSON has nested properties which I want to retain but I want to stringify only those objects that contain "units" and "value". All others should be listed as children items. Please help figure what I'm doing wrong.
Here's the json input:
{
"clusterName": "ml6.engrlab.com-cluster",
"statusProperties": {
"loadProperties": {
"loadDetail": {
"restoreWriteLoad": {
"value": 0,
"units": "sec/sec"
},
},
"totalLoad": {
"value": 0.0825921967625618,
"units": "sec/sec"
}
},
"secure": {
"value": false,
"units": "bool"
},
"statusDetail": {
"licenseKeyOption": [
{
"value": "conversion",
"units": "enum"
},
{
"value": "failover",
"units": "enum"
}
],
"connectPort": 7999,
"softwareVersion": {
"value": 9000100,
"units": "quantity"
}
},
"rateProperties": {
"rateDetail": {
"largeReadRate": {
"value": 0,
"units": "MB/sec"
}
},
"totalRate": {
"value": 67.2446365356445,
"units": "MB/sec"
}
},
"online": {
"value": true,
"units": "bool"
},
"cacheProperties": {
"cacheDetail": {
"tripleCachePartitions": {
"tripleCachePartition": [
{
"partitionSize": 768,
"partitionBusy": 0,
"partitionUsed": 0,
"partitionFree": 100
}
]
}
}
}
}
}
my code
function isNested(obj) {
if(!obj) return false;
let propArry = Object.keys(obj)
for(let i=0; i<propArry.length; i++){
if(obj[propArry[0]].constructor.name === 'Object') return true
}
return false;
}
function getKeyValueAsChildren(obj) {
let vals = [];
for(let key in obj) {
if(obj.hasOwnProperty(key)){
vals.push({key:key, value: obj[key]})
}
}
return vals
}
function valueAsString(obj) {
if(typeof obj !== 'object') return obj;
return `${obj['value']} ${obj['units']}`
}
function getChildren(key, obj) {
if(Object.keys(obj).sort().toString() === "units,value"){
return {key: key, value: valueAsString(obj)}
} else {
return {key: key, children: getKeyValueAsChildren(obj) }
}
}
function getValues(properties, values = []) {
for(let key in properties) {
if(properties.hasOwnProperty(key)) {
let value = properties[key]
if(typeof value !== 'object') {
values.push({key: key, value: value})
} else if(Array.isArray(value)){
let children = []
value.map(v => {
children.push(getChildren(key, v))
})
values.push({key: `${key}List`, children: children})
}
else if(value.constructor.name === 'Object' && isNested(value)){
// I THINK THE MAIN PROBLEM IS HERE
let keys = Object.keys(value)
let children = [];
keys.forEach(key => {
children.push({key: key, children: getValues(value[key])})
})
values.push({key: key, children: children})
}
else {
values.push(getChildren(key, value))
}
}
}
return values
}
getValues(hostProperties)
this returns
[
{
"key": "clusterName",
"value": "ml6.engrlab.com-cluster"
},
{
"key": "statusProperties",
"children": [
{
"key": "loadProperties",
"children": [
{
"key": "loadDetail",
"children": [
{
"key": "restoreWriteLoad",
"children": [
{
"key": "value",
"value": 0
},
{
"key": "units",
"value": "sec/sec"
}
]
}
]
},
{
"key": "totalLoad",
"value": "0.0825921967625618 sec/sec"
}
]
},
{
"key": "secure",
"children": [
{
"key": "value",
"value": false
},
{
"key": "units",
"value": "bool"
}
]
},
{
"key": "statusDetail",
"children": [
{
"key": "licenseKeyOptionList",
"children": [
{
"key": "licenseKeyOption",
"value": "conversion enum"
},
{
"key": "licenseKeyOption",
"value": "failover enum"
}
]
},
{
"key": "connectPort",
"value": 7999
},
]
},
{
"key": "rateProperties",
"children": [
{
"key": "rateDetail",
"children": [
{
"key": "largeReadRate",
"children": [
{
"key": "value",
"value": 0
},
{
"key": "units",
"value": "MB/sec"
}
]
}
]
},
{
"key": "totalRate",
"value": "67.2446365356445 MB/sec"
}
]
},
{
"key": "online",
"children": [
{
"key": "value",
"value": true
},
{
"key": "units",
"value": "bool"
}
]
},
{
"key": "cacheProperties",
"children": [
{
"key": "cacheDetail",
"children": [
{
"key": "tripleCachePartitions",
"children": [
{
"key": "tripleCachePartitionList",
"children": [
{
"key": "tripleCachePartition",
"children": [
{
"key": "partitionSize",
"value": 768
},
{
"key": "partitionBusy",
"value": 0
},
{
"key": "partitionUsed",
"value": 0
},
{
"key": "partitionFree",
"value": 100
}
]
}
]
}
]
}
]
}
]
}
]
}
]
but I need this
[
{
"key": "clusterName",
"value": "ml6.engrlab.com-cluster"
},
{
"key": "statusProperties",
"children": [
{
"key": "loadProperties",
"children": [
{
"key": "loadDetail",
"children": [
{
"key": "restoreWriteLoad",
"value": "0 sec/sec"
}
]
},
{
"key": "totalLoad",
"value": "0.0825921967625618 sec/sec"
}
]
},
{
"key": "secure",
"value": "false bool"
},
{
"key": "statusDetail",
"children": [
{
"key": "licenseKeyOptionList",
"children": [
{
"key": "licenseKeyOption",
"value": "conversion enum"
},
{
"key": "licenseKeyOption",
"value": "failover enum"
}
]
},
{
"key": "connectPort",
"value": 7999
}
]
},
{
"key": "rateProperties",
"children": [
{
"key": "rateDetail",
"children": [
{
"key": "largeReadRate",
"value": "0 MB/sec"
}
]
},
{
"key": "totalRate",
"value": "67.2446365356445 MB/sec"
}
]
},
{
"key": "online",
"value": "true bool"
},
{
"key": "cacheProperties",
"children": [
{
"key": "cacheDetail",
"children": [
{
"key": "tripleCachePartitions",
"children": [
{
"key": "tripleCachePartitionList",
"children": [
{
"key": "tripleCachePartition",
"children": [
{
"key": "partitionSize",
"value": 768
},
{
"key": "partitionBusy",
"value": 0
},
{
"key": "partitionUsed",
"value": 0
},
{
"key": "partitionFree",
"value": 100
}
]
}
]
}
]
}
]
}
]
}
]
}
]
You might have to run more tests, as what you require seems quite arbitrary, but I believe this function does what you are looking for. It works in a similar way to yours, by simply recursing the tree, and checking for object types, and if the special case is matched.
function toKeyValue(obj) {
return Object.keys(obj).map(k => {
var value = obj[k]
var key = k
var valueName = 'children'
if(Array.isArray(value)){
key = k + 'List'
value = value.map(toKeyValue)
}else if(value !== null && typeof value === 'object'){
// check for special case
if(Object.keys(value).sort().toString() === "units,value"){
value = value.value + ' ' + value.units
valueName = 'value'
}else{
value = toKeyValue(value)
}
}else{
valueName = 'value'
}
return {
key: key,
[valueName]: value
}
})
}
Fiddle here
I've an associative array from data source (which I don't control) like this:
{
"name": "foo",
"children": {
"#1": {
"count": 2,
"children": {
"#2": {
"count": 4,
"children": {
"#5": ...
}
},
"#4": {
"count": 3,
"children": {
"#6": ...
}
}
}
}
}
}
As you can see it's an ever-expanding tree structure using ids as keys. I would like to transform this into normal array so I can use lodash in the browser for a bit easier/faster manipulation.
The results should look like this:
{
"name": "foo",
"children": [
{
"id": "#1",
"count": 2,
"children": [
{
"id": "#2",
"count": 4,
"children": [...]
},
{
"id": "#4",
"count": 3,
"children": [...]
}
]
},
]
}
Transforming the objects isn't the problem but what I can't solve is how to do this recursively so that the structure doesn't get flatten and all children are under the right parent. I went through previous posts here but couldn't find anything that would help with this type of transformation.
You could use Object.keys (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) and a recursive function, like so
var a = {
"name": "foo",
"children": {
"#1": {
"count": 2,
"children": {
"#2": {
"count": 4,
"children": {
"#5": {}
}
},
"#4": {
"count": 3,
"children": {
"#6": {}
}
}
}
}
}
}
function convertKeysToArray(obj) {
if (obj.children !== undefined) {
var arr = []
Object.keys(obj.children).forEach(function(key) {
var child = obj.children[key];
convertKeysToArray(child);
child.id = key;
arr.push(child)
})
obj.children = arr;
}
}
convertKeysToArray(a)
console.log(JSON.stringify(a, null, " "))
var a = {
"name": "foo",
"children": {
"#1": {
"count": 2,
"children": {
"#2": {
"count": 4,
"children": {
"#5": {}
}
},
"#4": {
"count": 3,
"children": {
"#6": {}
}
}
}
}
}
}
function convertKeysToArray(obj) {
if (obj.children !== undefined) {
var arr = []
Object.keys(obj.children).forEach(function(key) {
var child = obj.children[key];
convertKeysToArray(child);
child.id = key;
arr.push(child)
})
obj.children = arr;
}
}
convertKeysToArray(a)
so.log(a)
<pre id="so"></pre>
<script>
var so = {
log: function (obj) {
document.getElementById("so").innerHTML = JSON.stringify(obj, null, " ");
}
}
</script>