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

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);

Related

Loop through complex JSON with 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)
)
})
})

structuring obj array based on their attributes [duplicate]

This question already has answers here:
How can I group an array of objects by key?
(32 answers)
Closed 1 year ago.
can you help me with this problem with js\react?
I'm trying to manage 2 arrays due to obtain a new object based on their shared attribute (Array A: "id" and Array B: "parent")
I think isn't hard but I'm struggling to do it atm :(
Array A
[{
"id": "606f1a2bebb5fb53804dd3d5",
"name": "cc",
}, {
"id": "606f1a30cfe84430c41dce88",
"name": "bb",
}, {
"id": "606f1a4ed2ff554e4ea11b82",
"name": "ff",
}]
Array B
[{
"id": "3344",
"color": "pink",
"parent": "606f1a2bebb5fb53804dd3d5",
}, {
"id": "3453",
"color": "blue",
"parent": "606f1a30cfe84430c41dce88",
}, {
"id": "3331",
"color": "yellow",
"parent": "606f1a4ed2ff554e4ea11b82",
}, {
"id": "4442",
"color": "black",
"parent": "606f1a30cfe84430c41dce88",
}]
I want merge these two arrays and create a new one where the array B objects are split by "id" of array A.
Something like this:
[{
"606f1a2bebb5fb53804dd3d5": [{
"id": "3344",
"color": "pink",
"parent": "606f1a2bebb5fb53804dd3d5",
}]
}, {
"606f1a30cfe84430c41dce88": [{
"id": "3453",
"color": "blue",
"parent": "606f1a30cfe84430c41dce88",
}, {
"id": "4442",
"color": "black",
"parent": "606f1a30cfe84430c41dce88",
}]
}, {
"606f1a4ed2ff554e4ea11b82": [{
"id": "3331",
"color": "yellow",
"parent": "606f1a4ed2ff554e4ea11b82",
}]
}]
Thanks very much guys
You just need array b for grouping and another object for keeping track of the max key inside of a group.
const
data = [{ id: "3344", color: "pink", parent: "606f1a2bebb5fb53804dd3d5" }, { id: "3453", color: "blue", parent: "606f1a30cfe84430c41dce88" }, { id: "3331", color: "yellow", parent: "606f1a4ed2ff554e4ea11b82" }, { id: "4442", color: "black", parent: "606f1a30cfe84430c41dce88" }],
max = {},
result = data.reduce((r, o) => {
max[o.parent] = (max[o.parent] || 0) + 1;
(r[o.parent] ??= {})[max[o.parent]] = o;
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think you can loop through the items and then find the parent
let arrayC = [];
arrayB.forEach(item => {
let parent = array1.find(e => e.id === item.parent);
// do something here to combine it into one object
// then arrayC.push(newItem);
});
https://codesandbox.io/s/boring-snowflake-brksj?file=/src/index.js
const result = arrayA.reduce((acc, arrayAItem) => {
return {
...acc,
[arrayAItem.id]: arrayB.filter(
(arrayBItem) => arrayBItem.parent === arrayAItem.id
)
};
}, {});
}]
You can do this with map and filter functions of array.
const newArray = array1.map(array1Item => {
return { [array1Item.id]: array2.filter(array2Item => array2Item.parent === array1Item.id)}
})
Based on the two arrays that you have, I assume that they are only linked by their "parent" ids. If this is the case, you can reduce the B array using the A array as an accumulator.
const a = [
{ "id": "606f1a2bebb5fb53804dd3d5" , "name": "cc" },
{ "id": "606f1a30cfe84430c41dce88" , "name": "bb" },
{ "id": "606f1a4ed2ff554e4ea11b82" , "name": "ff" },
];
const b = [
{ "id": "3344" , "color": "pink" , "parent": "606f1a2bebb5fb53804dd3d5" },
{ "id": "3453" , "color": "blue" , "parent": "606f1a30cfe84430c41dce88" },
{ "id": "3331" , "color": "yellow" , "parent": "606f1a4ed2ff554e4ea11b82" },
{ "id": "4442" , "color": "black" , "parent": "606f1a30cfe84430c41dce88" },
];
const c = Object
.entries(b.reduce((acc, { id, color, parent }) =>
({ ...acc, [parent]: {
...acc[parent],
colors: [...acc[parent].colors, { id, color } ]
}}),
Object.fromEntries(a.map(({ id, name }) =>
[ id, { name, colors: [] } ]))))
.map(([ id, value ]) => value);
console.log(c);
.as-console-wrapper { top: 0; max-height: 100% !important; }

How to add properties to nested object in array depending on conditions

I'm stuck once more with adding properties to a deeply nested array. What I do have is:
myArray = [
{
"id": "123",
"station": {
"id": 5,
"name": "Teststation"
},
"values": [
{
"id": "way",
"values": [ 339, 340, 341 ]
},
{
"id": "time",
"values": [ 1, 2, 3 ]
},
{
"name": "element_1",
"type": "line",
"result": "nok"
},
{
"name": "element_2",
"type": "rect",
"result": "nok"
},
{
"name": "element_3",
"type": "line",
"result": "ok"
}
]
}
]
myArray might contain more objects which would have the same structure like this one. So I have to loop them. What I want to achieve is:
I want to add properties to the object which own a propertiy called "line" or "rect" and the new property depends on the value of result
So the new outcome should look like:
myArray = [
{
"id": "123",
"station": {
"id": 5,
"name": "Teststation"
},
"values": [
{
"id": "way",
"values": [ 339, 340, 341 ]
},
{
"id": "time",
"values": [ 1, 2, 3 ]
},
{
"name": "element_1",
"type": "line",
"result": "nok"
"line": { color: 'red' }
},
{
"name": "element_2",
"type": "rect",
"result": "nok",
"opacity": 0.2,
"line": { color: 'gray', width: 0 },
"fillcolor": 'green'
},
{
"name": "element_3",
"type": "line",
"result": "ok"
"line": { color: 'green' }
}
]
}
]
What I tried so far seemed to work until I realized: It returns an array with an array with that object. I don't understand why it is doing so and how to get only an array with the object. Can anyone help me out on that?
addColor(myArray) {
return myArray.map(obj => {
for (const prop in obj) {
if (obj.hasOwnProperty(prop) && Array.isArray(obj[prop])) {
for (const item in obj[prop]) {
if (obj[prop][item].hasOwnProperty('result') && (obj[prop][item].type === 'line')) {
obj[prop][item].result === 'nok' ? obj[prop][item].line = { color: 'red' } : obj[prop][item].line = { color: 'green' };
} else if (obj[prop][item].hasOwnProperty('result') && (obj[prop][item].type === 'rect')) {
obj[prop][item].opacity = 0.2;
obj[prop][item].line = { color: 'gray', width: 0 };
obj[prop][item].result === 'nok' ? (obj[prop][item].fillcolor = 'red') : (obj[prop][item].fillcolor = 'green');
}
}
}
}
console.log('myArray out', myArray);
// It doesn't return anything so far so I added
return myArray
// But then I do get [[{}]]
});
}
Adding working snippet, with a small change in your code:
var myArray = [
{
"id": "123",
"station": {
"id": 5,
"name": "Teststation"
},
"values": [
{
"id": "way",
"values": [ 339, 340, 341 ]
},
{
"id": "time",
"values": [ 1, 2, 3 ]
},
{
"name": "element_1",
"type": "line",
"result": "nok"
},
{
"name": "element_2",
"type": "rect",
"result": "nok"
},
{
"name": "element_3",
"type": "line",
"result": "ok"
}
]
}
];
function addColor(myArray) {
const x = myArray.map(obj => {
for (const prop in obj) {
if (obj.hasOwnProperty(prop) && Array.isArray(obj[prop])) {
for (const item in obj[prop]) {
if (obj[prop][item].hasOwnProperty('result') && (obj[prop][item].type === 'line')) {
obj[prop][item].result === 'nok' ? obj[prop][item].line = { color: 'red' } : obj[prop][item].line = { color: 'green' };
} else if (obj[prop][item].hasOwnProperty('result') && (obj[prop][item].type === 'rect')) {
obj[prop][item].opacity = 0.2;
obj[prop][item].line = { color: 'gray', width: 0 };
obj[prop][item].result === 'nok' ? (obj[prop][item].fillcolor = 'red') : (obj[prop][item].fillcolor = 'green');
}
}
}
}
return obj; //<---- Check here
});
return x;
}
addColor(myArray);
const myArray = [{
"id": "123",
"station": {
"id": 5,
"name": "Teststation"
},
"values": [{
"id": "way",
"values": [339, 340, 341]
},
{
"id": "time",
"values": [1, 2, 3]
},
{
"name": "element_1",
"type": "line",
"result": "nok"
},
{
"name": "element_2",
"type": "rect",
"result": "nok"
},
{
"name": "element_3",
"type": "line",
"result": "ok"
}
]
}]
const modifiedArray = myArray.map(item => {
const newItem = Object.assign({}, item);
if (newItem.values) {
const newItemValues = newItem.values.map(value => {
const additionalProps = {};
if (value.type === 'line') {
additionalProps.line = {
color: (value.result === 'ok' && 'green') || 'red'
};
}
if (value.type === 'rect') {
additionalProps.opacity = 0.2;
additionalProps.line = {
color: 'gray',
width: 0
};
additionalProps.fillcolor = (value.result === 'ok' && 'green') || 'red';
}
const newValue = Object.assign({}, value, additionalProps);
return newValue;
});
newItem.values = newItemValues;
}
return newItem;
});
console.log('original:', myArray);
console.log('modified:', modifiedArray);

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