I want to group similar sub-item of my Json into one and then merge all their sub-item under that created item.
this is my json file:
{
"car": [
{
"name": "benz",
"details": [
{
"name": "C1",
"year": [
{
"name": "1850",
"errs": [
{
"user": "model-A",
"text": "error text on model-H"
},
{
"user": "model-C",
"text": "error text on model-C"
}
]
},
{
"name": "1820",
"errs": [
{
"user": "model-C",
"text": "error text on model-C"
}
]
}
]
}
]
},
{
"name": "vw",
"details": [
{
"name": "A1",
"year": [
{
"name": "1860",
"errs": []
},
{
"name": "1870",
"errs": [
{
"user": "model-A",
"text": "error text on model-H"
}
]
}
]
},
{
"name": "A2",
"year": [
{
"name": "1910",
"errs": []
},
{
"name": "1950",
"errs": [
{
"user": "model-A",
"text": "error text on model-H"
}
]
}
]
}
]
}
]
}
my tree structure is based on label and children, so my parent item is label and sub tree is children.
and this is my ts file:
ngOnInit():void {
this.http.get('.car.json').subscribe((data) => {
data.car.forEach((carItem) => {
carItem.details.forEach((detail) => {
const errorsTree = {};
detail.year.forEach((year) => {
year.errs.forEach((err) => {
let userNode;
let carNode;
let detailNode;
if (errorsTree[err.userAgent]) {
userNode = errorsTree[err.userAgent];
} else {
userNode = {name: err.userAgent, cars: {}};
errorsTree[err.userAgent] = userNode;
}
const components = userNode.cars;
if (components[carItem.name]) {
carNode = cars[carItem.name];
} else {
carNode = {name: carItem.name, details: {}};
components[carItem.name] = carNode;
}
const detailsItems = carNode.details;
if (detailsItems[detail.name]) {
detailNode = detailsItems[detail.name];
} else {
detailNode = {name: detail.name, tests: {}};
detailsItems[detail.name] = detailNode;
}
detailNode.tests[test.name] = test;
this.TreeModel.push({
label: userNode.name,
children: _.values(userNode.cars).map((car) => {
return {
label: car.name,
children: _.values(car.details).map((deta) => {
return {
label: deta.name,
children: _.values(deta.tests).map((testItem) => {
return {
label: testItem.name,
err: err.text
};
})
};
})
};
})
});
});
});
});
});
});
}
after running the code the tree will be like this:
model-A
benz
C1
model-C
benz
C1
model-C
benz
C1
model-A
vw
A1
model-A
vw
A2
but it is not correct, the result should be like following:
[
{
label: 'model-A',
children: [
{
label: 'benz',
children: [
{
label: 'C1'
}
]
},
{
label: 'vw',
children: [
{
label: 'A1'
},
{
label: 'A2'
}
]
}
]
},
{
label: 'model-C',
children: [
{
label: 'benz',
children: [
{
label: 'C1'
}
]
}
]
}
]
do you have i idea how to group this Json like the above structure with Angular 5
thanks.
You can use something like this -
var processedJSON = {};
const data = {
"car": [{
"name": "benz",
"details": [{
"name": "C1",
"year": [{
"name": "1850",
"errs": [{
"user": "model-A",
"text": "error text on model-H"
},
{
"user": "model-C",
"text": "error text on model-C"
}
]
},
{
"name": "1820",
"errs": [{
"user": "model-C",
"text": "error text on model-C"
}]
}
]
}]
},
{
"name": "vw",
"details": [{
"name": "A1",
"year": [{
"name": "1860",
"errs": []
},
{
"name": "1870",
"errs": [{
"user": "model-A",
"text": "error text on model-H"
}]
}
]
},
{
"name": "A2",
"year": [{
"name": "1910",
"errs": []
},
{
"name": "1950",
"errs": [{
"user": "model-A",
"text": "error text on model-H"
}]
}
]
}
]
}
]
};
data.car.forEach(function(car, i) {
car.details.forEach(function(detail, j) {
detail.year.forEach(function(year, k) {
year.errs.forEach(function(element, l) {
if (!processedJSON[element.user]) {
processedJSON[element.user] = {};
}
if (!processedJSON[element.user][car.name]) {
processedJSON[element.user][car.name] = [];
}
if (processedJSON[element.user][car.name].indexOf(detail.name) == -1) {
processedJSON[element.user][car.name].push(detail.name);
}
});
});
});
});
console.log(processedJSON);
You can structure your data using array#reduce with multiple array#forEach, then from this result, use array#map with Object.keys() to get the final format.
const data = { "car": [ { "name": "benz", "details": [ { "name": "C1", "year": [ { "name": "1850", "errs": [ { "user": "model-A", "text": "error text on model-H" }, { "user": "model-C", "text": "error text on model-C" } ] }, { "name": "1820", "errs": [ { "user": "model-C","text": "error text on model-C" } ] } ] } ] }, { "name": "vw", "details": [ { "name": "A1", "year": [ { "name": "1860", "errs": [] }, { "name": "1870", "errs": [ { "user": "model-A", "text": "error text on model-H" } ] } ] }, { "name": "A2", "year": [{ "name": "1910", "errs": [] }, { "name": "1950", "errs": [ { "user": "model-A", "text": "error text on model-H" } ] } ] } ] } ] },
result = data.car.reduce((r, {name, details}) => {
details.forEach(o1 => {
o1.year.forEach(o2 => {
o2.errs.forEach(({user, text}) => {
r[user] = r[user] || {};
r[user][name] = r[user][name] || [];
if(!r[user][name].includes(o1.name))
r[user][name].push(o1.name);
});
});
});
return r;
},{});
const output = Object.keys(result).map(k => ({label : k, children : Object.keys(result[k]).map(key => ({label: key, children : result[k][key].map(([label]) => ({label}) ) }) ) }) );
console.log(output);
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 JSON data:
{
"data": [
{
"category": {
"documentId": "c8kr0cv012vtr8vm3iug",
"title": "Art"
},
"subcategories": [
{
"documentId": "c8kr7nv012vtr8vm3l8g",
"title": "Architecture"
},
{
"documentId": "c8kr7nv012vtr8vm3lag",
"title": "Dance"
},
{
"documentId": "c8kr7nv012vtr8vm3lbg",
"title": "Fashion"
}
]
},
{
"category": {
"documentId": "c8kr0cv012vtr8vm3iqg",
"title": "Business"
},
"subcategories": [
{
"documentId": "c8kr3d7012vtr8vm3jjg",
"title": "Crypto"
},
{
"documentId": "c8kr3d7012vtr8vm3jj0",
"title": "Finance"
},
{
"documentId": "c8kr3d7012vtr8vm3jkg",
"title": "Marketing"
}
]
}
]
}
I have tagview in my mobile screen so user can select multiple subcategory at a same time by select deselect so if i choose 2 subcategory from Art and 2 from Business then expected post payload should be like below
{
"data": [
{
"category": "c8kr0cv012vtr8vm3iug",
"subcategories": [
"c8kr7nv012vtr8vm3l8g",
"c8kr7nv012vtr8vm3lag"
]
},
{
"category": "c8kr0cv012vtr8vm3iqg",
"subcategories": [
"c8kr3d7012vtr8vm3jjg",
"c8kr3d7012vtr8vm3jj0"
]
}
]
}
So my code is like below
const tempDefaultPayload = dataPayload.map(x => {
if (x.category) {
x.subcategories?.push(subcategory);
if (userData?.userInterests?.map(v => v.category.documentId === category)) {
const arrayNewData: any = [];
const newData: any = userData?.userInterests?.map(i =>
i.subcategories?.map(k => {
arrayNewData.push(k?.documentId);
return k?.documentId;
}),
);
x.subcategories?.push(...arrayNewData);
}
return x;
}
return x;
})
When I run above code payload is not passing correct
[
{
"category": "c8kr0cv012vtr8vm3iug",
"subcategories": [
"c8kr7nv012vtr8vm3l8g",
"c8kr7nv012vtr8vm3lag",
"c8kr3d7012vtr8vm3jjg",
"c8kr3d7012vtr8vm3jj0"
]
},
{
"category": "c8kr0cv012vtr8vm3iqg",
"subcategories": [
"c8kr7nv012vtr8vm3l8g",
"c8kr7nv012vtr8vm3lag",
"c8kr3d7012vtr8vm3jjg",
"c8kr3d7012vtr8vm3jj0"
]
}
]
It is passing all selected subcategory in both array any idea how can I solve this ?
If you have the selected tag ids in the array selectedTags and your json as a variable called data:
const tempDefaultPayload = {
data: data.data.map(x => {
"category": x.category.documentId,
"subcategories": x.subcategories.map(subcat =>
subcat.documentId).filter(item => selectedTags.includes(item))
})
}
Playground example
I've a json like below
[
{
"name": "Item",
"attribute_list": [
{
"name": "Attribute 1",
"value_list": [
{
"value": "1"
},
{
"value": "2"
}
]
},
{
"name": "Attribute 2",
"value_list": [
{
"value": "10"
},
{
"value": "60"
},
{
"value": "80"
}
]
}
]
}
]
I want to change format like below
[
{
"Item": [{
"Attribute 1": "1", "Attribute 2": "10"
}]
}
]
What I've done already:
results.map(items => {
data[items.name.toLowerCase().replace(/ /g, '_')] = items.attribute_list?
items.attribute_list.reduce(
(obj, item) => Object.assign(obj, { [item.name.toLowerCase().replace(/ /g, '_')]: item.value_list?item.value_list[0].value:null }), {})
:null
})
Thanks in advance
If I understood everything correctly, you can do it like this:
const input = [
{
"name": "Item",
"attribute_list": [
{
"name": "Attribute 1",
"value_list": [
{
"value": "1"
},
{
"value": "2"
}
]
},
{
"name": "Attribute 2",
"value_list": [
{
"value": "10"
},
{
"value": "60"
},
{
"value": "80"
}
]
}
]
}
];
const result = input.map((entry) => {
return {
[entry.name]: [entry.attribute_list.reduce((res, curr) => {
res[curr.name] = curr.value_list[0].value;
return res;
}, {})]
};
});
console.log(result);
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; }
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)