How to Convert nested json to array of object in Javascript? - javascript

I've a deep nested object like this:
{
'name_1': 'val',
'name_2': 'val',
'name_3': {
'name_4': {
'name_5': {
'name_6': 'val',
'name_7': 'val',
'name_8': {
'name_9': 'val'
}
}
}
}
}
Here key can be anything instead of name_1, name_2, name_3...etc(names key
as name_1, name_2.. just for quick understanding)
I wanted to convert the above json to array of objects in the below mentioned format
[
{ "id": "1", "name": 'name_1: val', "parent_id": "0"},
{ "id": "2", "name": 'name_2: val', "parent_id": "0"},
{ "id": "3", "name": 'name_3', "parent_id": "0"},
{ "id": "4", "name": 'name_4', "parent_id": "3"},
{ "id": "5", "name": 'name_5', "parent_id": "4"},
{ "id": "6", "name": 'name_6: val', "parent_id": "5"},
{ "id": "7", "name": 'name_7: val', "parent_id": "5"},
{ "id": "8", "name": 'name_8', "parent_id": "5"},
{ "id": "9", "name": 'name_9: val', "parent_id": "8"},
]
Any help would be really apprectiated!!

You could take an iterative and recursive approach. (The id is stored in an object to keep the same object reference for it and this allows to use it in all nested recursive calls.)
function flat(object, id = { id: 0 }, parent_id = 0) {
return Object.entries(object).reduce((r, [k, v]) => {
var name = k + (typeof v === 'string' ? ': ' + v : '');
r.push({ id: id.id++, name, parent_id });
if (v && typeof v === 'object') r.push(...flat(v, id, id.id));
return r;
}, []);
}
var data = { name_1: 'val', name_2: 'val', name_3: { name_4: { name_5: { name_6: 'val', name_7: 'val', name_8: { name_9: 'val' } } } } },
result = flat(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

sorting json tree with multiple property

i have prepared a json tree from a plain json. But i need to sort the tree with multiple conditions.
for example at level 1 we have multiple objects. we need to sort with level and then with a name property.
level is a number and name is an alphanumeric. so name sorting is alphabets first and then numbers
Below is the input json
var inputJson = [
{
"level": "1",
"leafFlag": "1",
"path":"p123",
"name":"food23"
},
{
"level": "1",
"leafFlag": "1",
"path":"r125",
"name":"car1"
},
{
"level": "2",
"leafFlag": "0",
"path":"p123/p345",
"name":"apple345"
},
{
"level": "2",
"leafFlag": "1",
"path":"p123/p095",
"name":"123banana"
},
{
"level": "3",
"leafFlag": "0",
"path":"p123/p095/p546",
"name":"543"
},
{
"level": "2",
"leafFlag": "1",
"path":"r125/yhes",
"name":"tata78"
}
]
var output = [];
The below code prepares the json tree.
I tried here for sorting with multiple properties
inputJson = inputJson.sort((a, b) => (parseInt(a.level) > parseInt(b.level)) ? 1 : -1)
inputJson.forEach(v => {
if (v.level == "1") {
v.children = [];
output.push(v);
}
else {
pathValues = v.path.split("/");
pathValues.pop();
var node = null;
var fullPath = "";
pathValues.forEach(p => {
fullPath = fullPath === "" ? p : fullPath + "/" + p;
node = (node == null ? output : node.children).find(o => o.path === fullPath);
})
node.children = node.children || [];
node.children.push(v);
}
})
Output from above:
var output = [
{
"level": "1",
"leafFlag": "1",
"path": "p123",
"name": "food23",
"children": [
{
"level": "2",
"leafFlag": "0",
"path": "p123/p345",
"name": "apple"
},
{
"level": "2",
"leafFlag": "1",
"path": "p123/p095",
"name": "banana",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "p123/p095/p546",
"name": "grapes"
}
]
}
]
},
{
"level": "1",
"leafFlag": "1",
"path": "r125",
"name": "car",
"children": [
{
"level": "2",
"leafFlag": "1",
"path": "r125/yhes",
"name": "tata",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "r125/yhes/sdie",
"name": "Range Rover"
}
]
},
{
"level": "2",
"leafFlag": "0",
"path": "r125/theys",
"name": "suzuki"
}
]
}
]
Expected output:
[
{
"level": "1",
"leafFlag": "1",
"path": "r125",
"name": "car",
"children": [
{
"level": "2",
"leafFlag": "0",
"path": "r125/theys",
"name": "suzuki"
},
{
"level": "2",
"leafFlag": "1",
"path": "r125/yhes",
"name": "tata",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "r125/yhes/sdie",
"name": "Range Rover"
}
]
}
]
},
{
"level": "1",
"leafFlag": "1",
"path": "p123",
"name": "food",
"children": [
{
"level": "2",
"leafFlag": "0",
"path": "p123/p345",
"name": "apple"
},
{
"level": "2",
"leafFlag": "1",
"path": "p123/p095",
"name": "banana",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "p123/p095/p546",
"name": "grapes"
}
]
}
]
}
]
I tried something like below
inputJson = inputJson.sort((a, b) => (parseInt(a.level) > parseInt(b.level)) ? 1 : -1 && a.name > b.name ? 1 ? -1)
You could take a single sort by sorting levels first and then by name.
.sort((a, b) => a.level - b.level || a.name.localeCompare(b.name))
Then build the tree with the sorted items.
var data = [{ level: "1", leafFlag: "1", path: "p123", name: "food" }, { level: "1", leafFlag: "1", path: "r125", name: "car" }, { level: "2", leafFlag: "0", path: "p123/p345", name: "apple" }, { level: "2", leafFlag: "1", path: "p123/p095", name: "banana" }, { level: "3", leafFlag: "0", path: "p123/p095/p546", name: "grapes" }, { level: "2", leafFlag: "1", path: "r125/yhes", name: "tata" }],
result = data
.sort((a, b) => a.level - b.level || a.name.localeCompare(b.name))
.reduce((r, o) => {
let p = o.path.split('/');
p.pop();
let target = p.reduce((t, _, i, p) => {
var path = p.slice(0, i + 1).join('/'),
temp = (t.children = t.children || []).find(q => q.path === path);
if (!temp) t.children.push(temp = { path }); // this is not necessary
// if all nodes are given
return temp;
}, { children: r });
(target.children = target.children || []).push({ ...o });
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var rootes= inputJson.filter(x=>x.level=='1')
for(i=0;i<rootes.length;i++){
rootes[i].children=[] }
var objwithchild = inputJson.filter(x=>x.leafFlag=='1')
for(i=0;i<objwithchild.length;i++){
objwithchild[i].children=[] }
inputJson.forEach(x=>{
patharr=x.path.split('/')
path=patharr.pop()
switch (x.level) {
case '2':
rootes.filter(p=>{if(p.path==patharr[0]){p.children.push(x)}
})
break
case '3':
objwithchild.filter(p=>{if(p.path==patharr[0]+'/'+patharr[1]){p.children.push(x)}
})
break
}
})
console.dir(rootes,{depth:null})
You should first sort by name, then re-sort the sorted array by level.
inputJson = inputJson.sort((a,b) => {return a.name > b.name}).sort((a,b) => {return (Number(a.level) - Number(b.level)};

Nested JSON - Join sub-object

How can I remove sub-objects?
[{
"id": "1",
"desc": "SOME PRODUCT",
"codigo": "CODE-28",
"codigoBarras": "2000000001",
"unidade": "PCT",
"price": "24.15",
"current_inventory": [{
"2kg": "5",
"5kg": "5",
"10kg": "5",
"20kg": "5",
"productId": "1"
}]
}]
[{
"id": "1",
"desc": "SOME PRODUCT",
"codigo": "CODE-28",
"codigoBarras": "2000000001",
"unidade": "PCT",
"price": "24.15",
"current_inventory_2kg": "5",
"current_inventory_5kg": "5",
"current_inventory_10kg": "5",
"current_inventory_20kg": "5",
}]
Use Object.keys() and a forEach loop
var x =[
{
"id": "1",
"desc": "SOME PRODUCT",
"codigo": "CODE-28",
"codigoBarras": "2000000001",
"unidade": "PCT",
"price": "24.15",
"current_inventory": [
{
"2kg": "5",
"5kg": "5",
"10kg": "5",
"20kg": "5",
"productId": "1"
}
]
}
]
x[0].current_inventory.forEach(e=>{
Object.keys(e).forEach(j=>{
x[0]['current_inventory_'+j]=e[j];
})
delete x[0].current_inventory
})
console.log(x)
Use Object.entries and reduce will simplify.
const data = [
{
id: "1",
desc: "SOME PRODUCT",
codigo: "CODE-28",
codigoBarras: "2000000001",
unidade: "PCT",
price: "24.15",
current_inventory: [
{
"2kg": 5,
"5kg": 5,
"10kg": 5,
"20kg": 5,
productId: 1
}
]
}
];
const [first] = data;
const updated = Object.entries(first).reduce((acc, [key, value]) => {
if (Array.isArray(value)) {
value.forEach(item =>
Object.entries(item).forEach(
([cKey, cValue]) => (acc[`${key}_${cKey}`] = cValue)
)
);
} else {
acc[key] = value;
}
return acc;
}, {});
console.log(updated);
THANK YOU VERY MUCH!!!
Solved using the code below:
data is de object
estoqueFracionado is the sub-object
for (let [key, value] of Object.entries(data)) {
value.estoqueFracionado.forEach (e => {
Object.keys(e).forEach(j => {
value['estoqueFracionado_' + j] = e[j]
})
delete value.estoqueFracionado
})
}

Creating a new array from the parents of array child element

I have the following array
{
"id": "111",
"name": "1111",
"children": [
{
"id": "22222",
"name": "2222",
"children": [
{
"id": "AAAA",
"name": "AAAA",
"children": [
{
"id": "DDD",
"name": "DDD"
},
{
"id": "EEE",
"name": "EEE"
}
]
},
{
"id": "BBBB",
"name": "BBB",
"children": [
{
"id": "FFF",
"name": "FFF"
},
{
"id": "GGG",
"name": "GGG",
"children": [
{
"id": "7777",
"name": "7777"
},
{
"id": "8888",
"name": "8888"
}
]
}
]
}
]
}
]
}
And I would like to create an array with the parents of a child by its ID.
So for example if I wanted to get the path to the child with ID "FFF", then the array would look like something like this:
["1111", "2222", "BBB", "FFF"]
How could I go about doing that?
You could take an iterative and recursive approach.
function getItems({ children, ...object }, key, value) {
var temp;
if (object[key] === value) return [object];
if (children) children.some(o => temp = getItems(o, key, value));
return temp && [object, ...temp];
}
var data = { id: "111", name: "1111", children: [{ id: "22222", name: "2222", children: [{ id: "AAAA", name: "AAAA", children: [{ id: "DDD", name: "DDD" }, { id: "EEE", name: "EEE" }] }, { id: "BBBB", name: "BBB", children: [{ id: "FFF", name: "FFF" }, { id: "GGG", name: "GGG", children: [{ id: "7777", name: "7777" }, { id: "8888", name: "8888" }] }] }] }] };
console.log(getItems(data, 'id', 'FFF'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could implement a recursive search to find all paths and return the correct one when you reach the desired name-value pair.
const isObject = (obj) => obj === Object(obj);
let data = loadData();
let expected = [ '1111', '2222', 'BBB', 'FFF' ];
let actual = findPath(data, 'name', 'FFF');
console.log(JSON.stringify(expected) === JSON.stringify(actual));
function findPath(data, key, value, includeIndicies=false) {
let opts = { found : null, includeIndicies : includeIndicies };
findPathInternal(data, key, value, opts, []);
return opts.found;
}
function findPathInternal(node, key, val, opts, path) {
if (Array.isArray(node)) {
for (let i = 0; i < node.length; i++) {
findPathInternal(node[i], key, val, opts, opts.includeIndicies ? path.concat(i) : path);
}
} else if (isObject(node)) {
if (node[key] === val) {
opts.found = path.concat(val); return; // Exit
} else {
let keys = Object.keys(node);
for (let i = 0; i < keys.length; i++) {
findPathInternal(node[keys[i]], key, val, opts, path.concat(node[key]));
}
}
}
};
function loadData() {
return {
"id": "111",
"name": "1111",
"children": [{
"id": "22222",
"name": "2222",
"children": [{
"id": "AAAA",
"name": "AAAA",
"children": [{
"id": "DDD",
"name": "DDD"
},
{
"id": "EEE",
"name": "EEE"
}
]
},
{
"id": "BBBB",
"name": "BBB",
"children": [{
"id": "FFF",
"name": "FFF"
},
{
"id": "GGG",
"name": "GGG",
"children": [{
"id": "7777",
"name": "7777"
},
{
"id": "8888",
"name": "8888"
}
]
}
]
}
]
}]
};
}
.as-console-wrapper { top: 0; max-height: 100% !important; }

Create new javascript object from 2 JSON objects grouped by id

I have below dynamic nested JSON object arrays and I wanted to get the desired output with JavaScript grouped by id from both.
First Array:
[
{
"id": "11",
"name": "emp1",
"location": [
{ "name": "abc", "id": "lc1" }
]
},
{
"id": "11",
"name": "emp2",
"location": [
{ "name": "abc", "id": "lc1" },
]
},
{
"id": "22",
"name": "emp3",
"location": [
{ "name": "xyz", "id": "lc2" }
]
}
]
Second array like below.
[
{
"name": "sub1",
"id": "11"
...
},
{
"name": "sub1.1",
"id": "11"
...
},
{
"name": "sub2",
"id": "22"
...
}
]
Desired Output:
[
{
"id": "11",
"first": [{"name": "emp1"},
{"name": "emp2"}],
"second": [{"name": "sub1"},{"name": "sub1.1"}],
"location": [{"name": "abc"}]
},
{
"id": "22",
"first": [{"name": "emp3"}],
"second": [{"name": "sub2"}],
"location": [{"name": "xyz"}]
}
]
How to get the desired output like above using javascript/angularjs?
I would do it using the amazing Array#reduce function.
Note that I have named your first array as a1, second as a2 and result as res.
a1.reduce(function(arr, obj) {
var existing = arr.filter(function(res) {
return res.id === obj.id
})[0]
if (existing) {
existing.first.push({
name: obj.name
})
} else {
var second = a2.filter(function(res) {
return res.id === obj.id
})
var secondObj = second.length ? second.map(function(sec) {
return {
name: sec.name
};
}) : []
arr.push({
id: obj.id,
first: [{
name: obj.name
}],
second: secondObj,
location: obj.location
})
}
return arr;
}, [])
Here's the working snippet. Take a look!
var a1 = [{
"id": "11",
"name": "emp1",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "11",
"name": "emp2",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "22",
"name": "emp3",
"location": [{
"name": "xyz",
"id": "lc2"
}]
}
]
var a2 = [{
"name": "sub1",
"id": "11"
}, {
"name": "sub1.1",
"id": "11"
},
{
"name": "sub2",
"id": "22"
}
]
var res = a1.reduce(function(arr, obj) {
var existing = arr.filter(function(res) {
return res.id === obj.id
})[0]
if (existing) {
existing.first.push({
name: obj.name
})
} else {
var second = a2.filter(function(res) {
return res.id === obj.id
})
var secondObj = second.length ? second.map(function(sec) {
return {
name: sec.name
};
}) : []
arr.push({
id: obj.id,
first: [{
name: obj.name
}],
second: secondObj,
location: obj.location
})
}
return arr;
}, [])
console.log(res)
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
var red1 = [{
"id": "11",
"name": "emp1",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "11",
"name": "emp2",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "22",
"name": "emp3",
"location": [{
"name": "xyz",
"id": "lc2"
}]
}
]
var b = [{
"name": "sub1",
"id": "11"
},
{
"name": "sub2",
"id": "22"
}
]
var identication = {}
var result = []
red1.forEach(function(val) {
if (val['id'] in identication) {
var t = {}
t['name'] = val['name']
result[identication[val['id']]]['first'].push(t)
} else {
var t = {}
t['name'] = val['name']
val['first'] = []
val['first'].push(t)
delete val['name']
var identity = result.push(val)
identication[val['id']] = identity - 1;
}
})
b.forEach(function(d) {
if (d['id'] in identication) {
var t = {
'name': d['name']
}
if (!('second' in result[identication[d['id']]])) {
result[identication[d['id']]]['second'] = []
}
result[identication[d['id']]]['second'].push(t)
} else {
var t = {}
for (key in d) {
if (key == 'name')
continue
t[key] = d[key]
}
t['second'] = [{
'name': d['name']
}]
var identity = result.push(t)
identication[d['id']] = identity - 1;
}
})
console.log(result)

javascript processing an array of objects to obtain a new array of objects

I need to obtain from a given array of objects another array of objects but a little bit processed. Example:
var arr = [
{
"level": "INF",
"model": "A"
},{
"level": "INF",
"model": "B"
},{
"level": "INF",
"model": "C"
},{
"level": "INC",
"model": "A"
},{
"level": "IND",
"model": "A"
},{
"level": "IND",
"model": "B"
}
]
process_array(arr)
should return:
[{
"level": "INF",
"model": "A-B-C"
},{
"level": "INC",
"model": "A"
},{
"level": "IND",
"model": "A-D"
}]
I mean, there only will be one object per different level and all the different models for that level will be concatenated by '-'.
What would be an easy way to achieve so?
My approach, for getting an array with different levels:
function process_array(array) {
var values_seen = {}; // for removing duplicates
for (var i = 0; i < array.length; i++) {
values_seen[array[i]["level"]] = true;
}
return Object.keys(values_seen);
}
Now i need to obtain the concatented models for each levels..
Just reduce the array into an object:
return array.reduce(function(total, current) {
if (total[current.level]) { // existing
total[current.level].model += '-' + current.model;
} else { // new
total[current.level] = current;
}
return total;
}, {});
Demo
In each iteration you modify the total object and then return it to be used within the next iteration. The final value of that object is returned to the caller.
See also Array.prototype.reduce()
var arr = [
{
"level": "INF",
"model": "A"
},{
"level": "INF",
"model": "B"
},{
"level": "INF",
"model": "C"
},{
"level": "INC",
"model": "A"
},{
"level": "IND",
"model": "A"
},{
"level": "IND",
"model": "B"
}
]
function processArray(array) {
var count = array.length, i, item, result = [], temp = {};
for (i = 0; i < count; i++) {
item = array[i];
if (temp[item.level] !== undefined) {
result[temp[item.level]].model += '-' + item.model;
} else {
temp[item.level] = result.length;
result.push(item);
}
}
return result;
}
alert(JSON.stringify(processArray(arr)));
What you are referring to is also called projection.
This code uses EcmaScript 5.
var arr = [
{
"level": "INF",
"model": "A"
},{
"level": "INF",
"model": "B"
},{
"level": "INF",
"model": "C"
},{
"level": "INC",
"model": "A"
},{
"level": "IND",
"model": "A"
},{
"level": "IND",
"model": "B"
}
];
function processArray(input) {
var buf = {}, result = [];
input.forEach(function(item) {
var model = item.model;
var existing = buf[item.level];
if (existing) {
existing.model += '-' + item.model;
} else {
existing = buf[item.level] = {
level: item.level,
model: model
};
result.push(existing);
}
});
return result;
}
var processed = processArray(arr);
console.log(processed);
function processArray(arr) {
var result = [];
arr
.map(function(v) {return v.level;})
.forEach(function(v, i) {
var resultValue = result.filter(function(el, j) {
return el.level === v;
})[0];
if(!resultValue) {
result.push(arr[i]);
} else {
resultValue.model += '-' + arr[i].model;
}
});
return result;
}
var arr = [
{
"level": "INF",
"model": "A"
},{
"level": "INF",
"model": "B"
},{
"level": "INF",
"model": "C"
},{
"level": "INC",
"model": "A"
},{
"level": "IND",
"model": "A"
},{
"level": "IND",
"model": "B"
}
];
alert(JSON.stringify(processArray(arr), null, 2));

Categories

Resources