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);
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 am stuck at this, where I want to set a combination for the variant object.
the variants data is:
"Variants": [
{
"name": "color",
"variants": [
{
"id": "e637bd15-d5e3-486b-aba3-3193cfb621bd",
"variantName": "red"
},
{
"id": "ee81a10d-5cdb-4e99-bc54-9f729025ff6b",
"variantName": "yellow"
}
],
"id": 1
},
{
"name": "size",
"variants": [
{
"id": "7546d9dd-410e-4bd7-99f2-cea7b5fd558b",
"variantName": "large"
},
{
"id": "e787b3c5-45db-4502-ab1b-dfe1670814fc",
"variantName": "small"
}
],
"id": 2
}
],
I want the console to print:
red/large, red/small, yellow/large, yellow/small.
but instead I get:
the code I wrote is:
const combinations = () => {
let result = [];
let len = data.length;
let i, j;
for (i = 0; i < len; i++) {
let len2 = data[i].variants.length;
for (j = 0; j < len2 - 1; j++) {
result.push(
data[j].variants[i].variantName +
'/' +
data[i].variants[j + 1].variantName
);
}
}
return console.log(result);
};
where did I go wrong? what I am missing, thx in advance.
you can achieve this using flatMap and map.
let data =[{name:"color",variants:[{id:"e637bd15-d5e3-486b-aba3-3193cfb621bd",variantName:"red"},{id:"ee81a10d-5cdb-4e99-bc54-9f729025ff6b",variantName:"yellow"}],id:1},{name:"size",variants:[{id:"7546d9dd-410e-4bd7-99f2-cea7b5fd558b",variantName:"large"},{id:"e787b3c5-45db-4502-ab1b-dfe1670814fc",variantName:"small"}],id:2}]
let a = data[0].variants.flatMap((color) => {
return data[1].variants.map((size) => `${color.variantName}/${size.variantName}`)
})
console.log(a)
If you want the cartesian product when the number of arrays is not explicitly specified can do something like this
reference
let data = [
{
"name": "color",
"variants": [
{
"id": "e637bd15-d5e3-486b-aba3-3193cfb621bd",
"variantName": "red"
},
{
"id": "ee81a10d-5cdb-4e99-bc54-9f729025ff6b",
"variantName": "yellow"
}
],
"id": 1
},
{
"name": "size",
"variants": [
{
"id": "7546d9dd-410e-4bd7-99f2-cea7b5fd558b",
"variantName": "large"
},
{
"id": "e787b3c5-45db-4502-ab1b-dfe1670814fc",
"variantName": "small"
},
{
"id": "e787b3c5-45dssb-4502-ab1b-dfe1670814fc",
"variantName": "medium"
}
],
"id": 2
},
{
"name": "weight",
"variants": [
{
"id": "7546d9dd-410e-4bd7-99f2-cea7b5fd558b",
"variantName": "heavy"
},
{
"id": "e787b3c5-45db-4502-ab1b-dfe1670814fc",
"variantName": "light"
}
],
"id": 3
},
{
"name": "material",
"variants": [
{
"id": "7546d9dd-410e-4bdhjh2-cea7b5fd558b",
"variantName": "plastic"
},
{
"id": "e787b3c5-45db-kkhkab1b-dfe1670814fc",
"variantName": "wood"
},
{
"id": "e787b3c5-45dbhhab1b-dfe1670814fc",
"variantName": "cement"
},
],
"id": 4
}
]
let combined = data.reduce((a,{variants})=>{
return a.flatMap(x=>variants.map(y=>x.concat(y.variantName)))
},[[]]).map((z) => z.join("/"))
console.log(combined)
I need to get the parent id of the specific child.
Here is my sample JSON, If I give entity id 32 it should return 6 as parent Id and if I give 30 it should return 5 as parent id.
const arr = [{
"id": 0,
"name": "My Entity",
"children": [
{
"id": 1,
"name": "MARKET",
"children": [
{
"id": 2,
"name": "Sales",
"children": [
{
"id": 3,
"name": "District 1",
"children": [
{
"id": 5,
"name": "Area 1",
"children": [
{
"entityId": 30,
"id": 26,
"name": "Mumbai"
},
{
"entityId": 31,
"id": 26,
"name": "Hyderabad"
}
],
"num": 0,
},
{
"id": 6,
"name": "Area 2",
"children": [
{
"entityId": 32,
"id": 32,
"name": "Karnataka"
},
{
"entityId": 33,
"id": 33,
"name": "Andhra Pradesh"
}
],
"num": 0,
},
]
},
]
},
]
},
]
}]
Here is the code I have tried
const findParent = (arr, entityId) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i].entityId === entityId) {
return [];
} else if (arr[i].children && arr[i].children.length) {
const t = findParents(arr[i].children, entityId);
if (t !== false) {
t.push(arr[i].id);
return t;
}
}
}
return false;
};
findParents(arr, 30);
But it is returning like below
[
5,
3,
2,
1,
0
]
But I want the output to be
[
5
]
Kindly help me on this, thanks
Replace this:
t.push(arr[i].id);
with:
if (t.length == 0) t.push(arr[i].id);
I would suggest easier solution
const findParent = (arr, entityId) => {
const children = arr.flatMap(parent =>
(item.children || []).map(child => ({ parent, child, entityId: child.entityId }))
)
const res = children.find(item => item.entityId === entityId)
return res.entityId || findChildren(res.map(v => v.child), entityId)
}
Currently I have the below object structure,
`let selectedOptions = {
"color": {
"id": "2",
"values": [
{
"value": "red",
"label": "Red",
"id": 1
},
{
"value": "blue",
"label": "Blue",
"id": 2
}
]
},
"size": {
"id": "19",
"values": [
{
"value": "medium",
"label": "Medium",
"id": 2
}
]
},
"demo": {
"id": "19",
"values": [
{
"value": "neylon",
"label": "Neylon",
"id": 2
}
]
}
.
.
.
N
}; `
And want to create array of objects from the above object like as below,
[
{ color: "red", size: "medium", demo: "neylon" },
{ color: "blue", size: "medium", demo: "neylon" }
]
I have tried like below but it didn't worked
https://jsfiddle.net/6Lvb12e5/18/
let cArr = [];
for(key in selectedOptions) {
selectedOptions[key].values.forEach(function(val,i) {
cArr.push({ [key]: val.value })
})
}
Thanks
You could take the wanted parts, like color, size and demo and build a cartesian product out of the given data.
const
cartesian = (a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []),
options = { color: { id: "2", values: [{ value: "red", label: "Red", id: 1 }, { value: "blue", label: "Blue", id: 2 }] }, size: { id: "19", values: [{ value: "small", label: "Small", id: 1 }, { value: "medium", label: "Medium", id: 2 }] }, demo: { id: "19", values: [{ value: "neylon", label: "Neylon", id: 2 }] } },
parts = Object
.entries(options)
.map(([k, { values }]) => [k, values.map(({ value }) => value)]),
keys = parts.map(([key]) => key),
result = parts
.map(([, values]) => values)
.reduce(cartesian)
.map(a => Object.assign(...a.map((v, i) => ({ [keys[i]]: v }))));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am not sure that is this the best way to do this, and even the data is missing but as a comment, it is quite big to post but can try:
let selectedOptions = {
"color": {
"id": "2",
"values": [
{
"value": "red",
"label": "Red",
"id": 1
},
{
"value": "blue",
"label": "Blue",
"id": 2
}
]
},
"size": {
"id": "19",
"values": [
{
"value": "medium",
"label": "Medium",
"id": 2
}
]
},
"demo": {
"id": "19",
"values": [
{
"value": "neylon",
"label": "Neylon",
"id": 2
}
]
}
};
let cArr = [];
var obj = {};
var glob;
for(key in selectedOptions) {
selectedOptions[key].values.forEach(function(val,i) {
obj[key] = val.value;
}
)
glob = obj;
}
cArr.push(glob);
console.log(cArr)
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