Loop through complex JSON with JavaScript - javascript

guys i have the following JSON
"detailed_statistics": [
{
"internal_key": "CORR",
"divider_name": "Corrosion Features",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Internal",
"hex_colour": "#d0320e",
"value": "386"
},
{
"plain_naming": "External",
"hex_colour": "#0000ff",
"value": "504"
}
]
}
]
},
{
"internal_key": "MILL",
"divider_name": "Manufacturing Features",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Internal",
"hex_colour": "#d0320e",
"value": "737"
},
{
"plain_naming": "External",
"hex_colour": "#0000ff",
"value": "54"
}
]
}
]
},
{
"internal_key": "DENT",
"divider_name": "Dent Features",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Unclassified",
"hex_colour": "#000000",
"value": "53"
}
]
}
]
},
{
"internal_key": "WELD_ANOM",
"divider_name": "Weld Anomalies",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Unclassified",
"hex_colour": "#000000",
"value": "2"
}
]
}
]
},
{
"internal_key": "OANOM",
"divider_name": "Complex Anomalies Not Otherwise Classified",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Unclassified",
"hex_colour": "#000000",
"value": "51"
}
]
}
]
}
]
what i want is to dig into the data [] and get lets say the value and store it into a separate array and from there i want to pass it to a pie chart as a parameter in order to built a pie. the way i am doing it i get the response as below:
(7) ['386', '504', '737', '54', '53', '2', '51']
however what the response i want is :
(5) [['386', '504'],[ '737', '54'], '53', '2', '51']
how i achieve the above result ? the first 2 values needs to be grouped together as the belong to the same "family" if that make sense. i want to use either forEach or for loop Javascript/ typescript
they way i am doing it and doesnt work for me is:
this.myData[0].detailed_statistics.forEach(value => {
console.log("this is the value", value.plots)
value.plots.forEach(val => {
console.log("is this the titles?", val.chart_title)
this.plotTitles.push(val.chart_title)
this.plotRadius.push(val.radius)
val.data.forEach(plt => {
this.plotPlainName.push(plt.plain_naming)
this.plotValue.push(plt.value)
this.plotColor.push(plt.hex_colour)
})
});
})

You can do this to retrieve the values in the form that you want:
const result = this.myData[0].detailed_statistics
.map(stat => stat.plots
.map(plot => plot.data
.map(data => data.value)
)
)
.flat()
.map(values => values.length === 1
? values[0]
: values
)
If you want to stick with something similar to what you have, but where the plotPlainName, plotValue and plotColor arrays all follow the requested format, then you could do something like this:
this.myData[0].detailed_statistics.forEach(stat => {
stat.plots.forEach(plot => {
this.plotTitles.push(plot.chart_title)
this.plotRadius.push(plot.radius)
this.plotPlainName.push(
plot.data.length === 1
? plot.data[0].plain_naming
: plot.data.map(data => data.plain_naming)
)
this.plotValue.push(
plot.data.length === 1
? plot.data[0].value
: plot.data.map(data => data.value)
)
this.plotColor.push(
plot.data.length === 1
? plot.data[0].hex_colour
: plot.data.map(data => data.hex_colour)
)
})
})

Related

nest items in JSON based on value?

Trying to get my head around this one..
Incoming data looks like:
[
{
"value": {
"label": "MZ Algal bloom",
"type": "case",
"incident": {
"name": "Algal bloom"
},
"personName": "Lionel Carter"
}
},
{
"value": {
"label": "BW Algal bloom",
"type": "case",
"incident": {
"name": "Algal bloom"
},
"personName": "Jerome Yost"
}
},
{
"value": {
"label": "Detergent",
"type": "case",
"incident": null,
"personName": "Jerald Legros"
}
}
]
I would like to transform this into
[
{
"label": "Algal bloom",
"children": [
{ "label": "Lionel Carter", "type": "case"},
{ "label": "Jerome Yost", "type": "case" }]
},
{ "label": "Detergent", "type": "case" }
]
Basically, the rule is that if incident is not NULL then the incident name becomes the parent and the children hold the personName - otherwise we simply pass through the label and type. I can walk the array and switch out the label with the incident name, but I'm not sure how to group up the incidents..
It's basic grouping with an exception for elements without incident.
You can group the elements without incident in a separate group:
const data = [{"value": {"label": "MZ Algal bloom","type": "case","incident": {"name": "Algal bloom"},"personName": "Lionel Carter"}},{"value": {"label": "BW Algal bloom","type": "case","incident": {"name": "Algal bloom"},"personName": "Jerome Yost"}},{"value": {"label": "Detergent","type": "case","incident": null,"personName": "Jerald Legros"}}];
function group(data) {
const result = data.reduce((acc, { value }) => {
if (!value.incident) {
acc.ungrouped.push({ label: value.label, type: value.type });
} else {
if (!acc.groups[value.incident.name]) acc.groups[value.incident.name] = { label: value.incident.name, children: [] };
acc.groups[value.incident.name].children.push({ label: value.personName, type: value.type });
}
return acc;
}, { groups: {}, ungrouped: [] });
return [...Object.values(result.groups), ...result.ungrouped];
}
console.log(group(data));

Filter and get data from JSON

How to get the data value from the list, the size of the array, the main thing is not through the index, because the order of the arrays can change and I can get specific data from the code === "size". Unfortunately, the structure cannot be changed. It came to mind only through the filter, by index, but it is impossible
The result should be 100 150
https://jsoneditoronline.org/#left=cloud.b10638604c214b189f87747414e06035
[
[
"color",
{
"name": "Цвет",
"code": "color",
"list": [
{
"value": "Зеленый"
},
{
"value": "Красный"
}
]
}
],
[
"size",
{
"name": "Размер",
"code": "size",
"list": [
{
"value": "100"
},
{
"value": "150"
}
]
}
]
]
This data structure is terrible, but a quick fix could be something like this
const data = [
[
"color",
{
"name": "Цвет",
"code": "color",
"list": [
{
"value": "Зеленый"
},
{
"value": "Красный"
}
]
}
],
[
"size",
{
"name": "Размер",
"code": "size",
"list": [
{
"value": "100"
},
{
"value": "150"
}
]
}
]
]
const size = data.filter(element => element[1].code === 'size')[0][1].list.map(element => element.value)
console.log(size)

How can I get a value from object in an array? [duplicate]

This question already has answers here:
How to find object in array by property in javascript?
(3 answers)
Closed 9 months ago.
Given the following, how can I get the value for shape from the object to a variable?
var data =
[
{
"Category": "Color",
"Options": [
{
"Key": "color",
"Value": "red"
}
]
},
{
"Category": "Shape",
"Options": [
{
"Key": "shape",
"Value": "circle"
}
]
}
];
var shape = // want this to be 'circle'
if you need the whole object you can use find or you can use reduce to get just what you need or you can get all the options with flatMap and than find the option you need
var data =
[
{
"Category": "Color",
"Options": [
{
"Key": "color",
"Value": "red"
}
]
},
{
"Category": "Shape",
"Options": [
{
"Key": "shape",
"Value": "circle"
}
]
}
];
const shape = data.find(d => d.Category === 'Shape')
const shapeOption = data.reduce((res, d) => {
if(d.Category === 'Shape'){
return d.Options.find(o => o.Key === 'shape').Value
}
return res
}, null)
const shapeWithTransformations = data.flatMap(d => d.Options).find((o) => o.Key === 'shape').Value
console.log(shape)
console.log(shapeOption)
console.log(shapeWithTransformations)
In your case it will be
var data =
[
{
"Category": "Color",
"Options": [
{
"Key": "color",
"Value": "red"
}
]
},
{
"Category": "Shape",
"Options": [
{
"Key": "shape",
"Value": "circle"
}
]
}
];
const shape = data[1]['Options'][0]['Value'];
console.log(shape);
But your structure is over complicated, if you have control over it then it should be something like
const data =
{
'Color': {
'Key': 'color',
'Value': 'red'
},
'Shape': {
'Key': 'shape',
'Value': 'circle'
}
};
const shape = data['Shape']['Value'];
console.log(shape);

Filtering nested JSON array in javascript and returning inner array which matches a criteria

I have a json object like this:
{
"products": [
{
"ID": "001",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Green"
},
{
"value": "Size",
"identifier": "L"
}
],
"SKUs": [
{
"ID": "001_1",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Green"
},
{
"value": "Size",
"identifier": "L"
}
]
},
{
"ID": "001_2",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Yellow"
},
{
"value": "Size",
"identifier": "M"
}
]
}
]
},
{
"ID": "002",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Size",
"identifier": "L"
}
],
"SKUs": [
{
"ID": "002_1",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Black"
},
{
"value": "Size",
"identifier": "L"
}
]
},
{
"ID": "002_2",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Grey"
}
]
}
]
},
{
"ID": "003",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Blue"
}
],
"SKUs": []
}
]
}')
As you can see, products is an array which contains another array SKUs which contains another array Attributes.
I want to get all those SKUs which have BOTH the attributes - Size and Color for them.
So, it should return
SKUs 001_1, 001_2 and 002_1
So, i wrote the following code:
var obj = JSON.parse('<MyAboveJSONObjectHere>');
obj.products.filter( p => p.SKUs.filter(sku => sku.Attributes.filter(att =>
att.identifier === 'Color' && att.identifier === 'Size')))
But this is returning all 3 product objects inside the JSON.
Can you please tell what is wrong with my code expression ?
With reduce":
data.products.reduce((p, c) => (
(c.SKUs = c.SKUs.filter(
sku =>
sku.Attributes.some(att => att.value === "Color") &&
sku.Attributes.some(att => att.value === "Size")
)).length && p.push(c), p ),[]
);
data = {
products: [
{
ID: "001",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Green"
},
{
value: "Size",
identifier: "L"
}
],
SKUs: [
{
ID: "001_1",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Green"
},
{
value: "Size",
identifier: "L"
}
]
},
{
ID: "001_2",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Yellow"
},
{
value: "Size",
identifier: "M"
}
]
}
]
},
{
ID: "002",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Size",
identifier: "L"
}
],
SKUs: [
{
ID: "002_1",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Black"
},
{
value: "Size",
identifier: "L"
}
]
},
{
ID: "002_2",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Grey"
}
]
}
]
},
{
ID: "003",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Blue"
}
],
SKUs: []
}
]
};
console.log(data.products.reduce((p, c) => (
(c.SKUs = c.SKUs.filter(
sku =>
sku.Attributes.some(att => att.value === "Color") &&
sku.Attributes.some(att => att.value === "Size")
)).length && p.push(c), p ),[]
));
If I understand correctly you're wanting to obtain a list of SKU ID values from the supplied products array where those SKU items has Attribute sub-arrays which contained values of "Color" and "Size".
This can be achieved via a reduce(), where the reduction callback filters SKU items based on the Attributes criteria. Any filtered SKU items are then mapped to their ID field, and collected (via concat()) into the resulting output array as shown below:
const obj={"products":[{"ID":"001","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Green"},{"value":"Size","identifier":"L"}],"SKUs":[{"ID":"001_1","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Green"},{"value":"Size","identifier":"L"}]},{"ID":"001_2","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Yellow"},{"value":"Size","identifier":"M"}]}]},{"ID":"002","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Size","identifier":"L"}],"SKUs":[{"ID":"002_1","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Black"},{"value":"Size","identifier":"L"}]},{"ID":"002_2","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Grey"}]}]},{"ID":"003","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Blue"}],"SKUs":[]}]};
/* Filter each product by the required SKU/attribute criteria */
const result = obj.products.reduce((output, product) => {
/* Determine if this products SKUs have contain requied attribute values */
return output.concat(product.SKUs.filter((sku) => {
const attributes = sku.Attributes;
/* Search the attributes of this sku, looking for any with values that
are color or size */
const hasColor = attributes.some((attribute) => attribute.value === 'Color');
const hasSize = attributes.some((attribute) => attribute.value === 'Size');
/* If both attribute values found then this sku matches required criteria */
return hasColor && hasSize;
})
/* Map any filtered sku to it's ID and concat the result to output */
.map(sku => sku.ID));
}, []);
console.log(result);
obj.products.map( p => {
return p.SKUs.map(sku => {
return sku.Attributes.filter(att => att.identifier === 'Color' && att.identifier === 'Size')}}
Try this, basically you need to first map through the arrays and only on the last one filter
I believe that you have to check value instead of identifier. Based on your object the value you are checking for is in the value key of the attribute object. You should also be checking for the array length of the return value of the inner filters. An empty array if passed in a condition will still be considered true that's why your filter always returns all the contents of your object. so the filter should look something like this.
obj.products.filter( p => p.SKUs.filter( att => att.Attributes.filter(inner => inner.value == 'Color' || inner.value == 'Size').length > 0 ? true : false).length > 0 ? true : false)

JS How to remove an object from array in a forEach loop?

I have a data object with following contents:
{
"content": {
"id": "someID",
"type": "unit",
"method": "xyz",
"blocks": [{
"key": "blue",
"data": [
"Array"
]
}, {
"key": "red",
"data": [
"Array"
]
}, {
"key": "yellow",
"data": [
"Array"
]
}, {
"key": "black",
"data": [
"Array"
]
}],
"notes": "abc"
}
}
I want to remove block that has key yellow, by looping over blocks, rest of the data should be preserved as is. So expected end result would be
{
"content": {
"id": "someID",
"type": "unit",
"method": "xyz",
"blocks": [{
"key": "blue",
"data": [
"Array"
]
}, {
"key": "red",
"data": [
"Array"
]
}, {
"key": "black",
"data": [
"Array"
]
}],
"notes": "abc"
}
}
Data is dynamic so I dont know what would be returned, it might have a match for my condition or it might not.
I've tried a bunch of approaches but nothing seems to have worked so far. I can use lodash too if its any easier. None of those seems to be working. Any help/direction is appreciated
1. Using **delete**
const deleteUnwantedBlock = contentObj => {
const updatedData = contentObj;
const blocks = _.get(updatedData, 'blocks', []);
blocks.forEach(block => {
if (block.key.includes('yellow')) {
delete updatedData.block;
}
});
return updatedData;
};
console.log(deleteUnwantedBlock(data.content));```
2. Using rest operator:
const deleteUnwantedBlock = contentObj => {
const blocks = _.get(contentObj, 'blocks', []);
blocks.forEach(block => {
if (block.key.includes('yellow')) {
let { block, ...restOfTheData } = updatedData;
}
return { ...updatedEntry };
});
};
console.log(deleteUnwantedBlock(data.content));
You just need to filter:
const obj = {
"content": {
"id": "someID",
"type": "unit",
"method": "xyz",
"blocks": [{
"key": "blue",
"data": [
"Array"
]
}, {
"key": "red",
"data": [
"Array"
]
}, {
"key": "yellow",
"data": [
"Array"
]
}, {
"key": "black",
"data": [
"Array"
]
}],
"notes": "abc"
}
};
obj.content.blocks = obj.content.blocks.filter(({ key }) => key !== 'yellow');
console.log(obj);

Categories

Resources