How to use find objects in multiple levels of nested arrays - javascript

What I want is to find an object in a nested array, and to get it by a pre-known ScheduleId number, and where the Duration property is defined.
We need to find this element which is contained inside of array of "Columns", and "Columns" are contained within "Table" elements.
After finding this object, I want to update ScheduleId = 0 and Duration = 0.
Sample data:
var data = {
"Headers": [
"A",
"B",
"C",
"D"
],
"Table": [
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 12,
},
],
},
{
"Columns": [
{
"Duration": 22,
"ScheduleId": 44,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 1648,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 22,
},
],
},
]
};
Pseudo code:
var requestedScheduleId = 22;
var requestedObj = data.Table.find(x => requestedScheduleId.Equals(x.Columns.ScheduleId) )
requestedObj.ScheduleId = 0;
requestedScheduleId.Duration = 0;
Unsuccessful attempt:
var test = data.Table.map(({ Columns }) => {return Columns = Columns.filter(({ ScheduleId }) => ScheduleId == 22 )});
console.log(test);

I would not use .map or .filter for this. It's a plain and simple nested loop: For each table, for each column, if condition is met, do something.
Either with for loops:
for (table of data.Table) {
for (column of table.Columns) {
if (column.ScheduleId === 22) {
column.ScheduleId = 0;
column.Duration = 0;
}
}
}
or with Array#forEach:
data.Table.forEach(table => {
table.Columns.forEach(column => {
if (column.ScheduleId === 22) {
column.ScheduleId = 0;
column.Duration = 0;
}
});
});
var data = {
"Headers": [
"A",
"B",
"C",
"D"
],
"Table": [
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 12,
},
],
},
{
"Columns": [
{
"Duration": 22,
"ScheduleId": 44,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 1648,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 22,
},
],
},
]
};
var requestedScheduleId = 22;
data.Table.forEach(table => {
table.Columns.forEach(column => {
if (column.ScheduleId === requestedScheduleId) {
column.ScheduleId = 0;
column.Duration = 0;
}
});
});
console.log(data);

Related

Replacing values in array which are received as argument of a method

In this array children array can have more childrens. I have a method in which I will get "lowValue" and "highValue". "Id" will be unique. when my method get called I need to use this unique id and replace old values of "lowValue" and "highValue" with the new ones. How can I do that?
// put your code here
<script>
myData = [{
"data": {
"name": "Applications",
"size": "200mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 1,
"name": "editor.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
}
},
{
"data": {
"id": 2,
"name": "settings.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
"mappedPersonaCount": 0,
}
}
]
},
{
"data": {
"name": "Cloud",
"size": "20mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 5,
"name": "backup-1.zip",
"highValue": 20,
"ratingID": 0,
"lowValue": 10
}
}]
}
]
</script>
Simple
const data = your_original_data
function replacer(lowValue, highValue, id){
for(let i = 0; i < data.length; i++){
for(let j = 0; j < data[i].children.length; j++){
if(data[i].children[j].data.id === id){
data[i].children[j].data.lowValue = lowValue
data[i].children[j].data.highValue = highValue
return
}
}
}
}
const myData = [{
"data": {
"name": "Applications",
"size": "200mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 1,
"name": "editor.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
}
},
{
"data": {
"id": 2,
"name": "settings.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
"mappedPersonaCount": 0,
}
}
]
},
{
"data": {
"name": "Cloud",
"size": "20mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 5,
"name": "backup-1.zip",
"highValue": 20,
"ratingID": 0,
"lowValue": 10
}
}]
}
]
const indexMap = new Map()
const parseDataToMap = (data = []) => {
data.forEach(e => {
if (e.children) {
e.children.forEach(e => {
indexMap.set(e.data.id, e.data)
})
}
})
}
parseDataToMap(myData)
console.log(myData[0].children[0].data)
const o = indexMap.get(1)
o.highValue = 25
o.lowValue = 11
console.log(myData[0].children[0].data)
Given the below-mentioned assumptions:
All children where id matches the supplied value will have the lowValue and highValue replaced.
The supplied id will always be present in the myData array in one or more children.
the following is one possible solution to achieve the desired result:
const replaceValues = (id = 5, lv = 5, hv = 50, arr = myData) => (
arr.reduce((f, i) => [...f, {
...i,
children: i.children.map(
child => ({
...child,
data: {
...child.data,
...(
child.data.id === id ? {
lowValue: lv,
highValue: hv
} : {}
)
}
})
)
}], [])
);
Explanation / Approach
The outer .reduce helps to iterate through the myData array
Each element in this array is placed as-is (using the ... spread operator)
Next, the children prop of each myData element is specified
Within this, i.children array is iterated using map to access each element
Each element here (again) is placed as-is using the ... spread-operator
Next, data is specified
Values for the data object are also spread (as before)
Then, if the data.id matches the parameter id then, lowValue and highValue are updated (using parameters lv and hv, respectively)
The ...( some_condition ? {k: v} : {} ) is one way to update an object's specific prop/s only when some_condition is true
Please use comments below to ask for further clarification/s.
Code Snippet
const myData = [{
"data": {
"name": "Applications",
"size": "200mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 1,
"name": "editor.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
}
},
{
"data": {
"id": 2,
"name": "settings.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
"mappedPersonaCount": 0,
}
}
]
},
{
"data": {
"name": "Cloud",
"size": "20mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 5,
"name": "backup-1.zip",
"highValue": 20,
"ratingID": 0,
"lowValue": 10
}
}]
}
];
const replaceValues = (id = 5, lv = 5, hv = 50, arr = myData) => arr.reduce((f, i) => [...f, {
...i,
children: i.children.map(
child => ({
...child,
data: {
...child.data,
...(
child.data.id === id ? {
lowValue: lv,
highValue: hv
} : {}
)
}
})
)
}], []);
console.log('replace id: 5, low: 5, high: 50', replaceValues());
console.log('replace id: 1, low: 11, high: 21', replaceValues(1, 11, 21));

how to change the format of json array by loping over

Hi I am getting data from API but I want my data in different format so that I can pass later into a function. I want to change the names of keys into a different one becasuse I have created a chart and it only draws if I send it data in certain way
This is what I am getting from API
data = {
"status": "success",
"from": "DB",
"indice": "KSE100",
"data": [
{
"stock_sector_name": "Tc",
"sector_score": "0828",
"stocks": [
{
"stock_symbol": "TRG",
"stock_score": 44
},
{
"stock_symbol": "SYS",
"stock_score": 33
}
]
},
{
"stock_sector_name": "OIL",
"sector_score": "0828",
"stocks": [
{
"stock_symbol": "FFS",
"stock_score": 44
},
{
"stock_symbol": "SMS",
"stock_score": 33
}
]
},
]
}
But I want my data to look like this like this
data = {
"name": "KSE100",
"children": [
{
"name": "A",
'points': -9,
"children": [
{
"stock_title": "A",
"value": 12,
},
{
"stock_title": "B",
"value": 4,
},
]
},
{
"name": "B",
'points': 20,
"children": [
{
"stock_title": "A",
"value": 12,
},
{
"name": "B",
"value": 4,
},
]
},
]
}
Like I want to replace
stock_sector_name = name
sector_score = value
stocks = children
stock_symbol = name
stock_score = value
I have been trying this for so much time but sill could not figured it out
function convert(d){
return {
name : d.indice,
children : d.data.map(y=>{
return {
name : y.stock_sector_name,
points : y.sector_score,
children : y.stocks.map(z=>{
return {
stock_title: z.stock_symbol,
value : z.stock_score
}
})
}
})
}
}
You can do something like this
const data = {
"status": "success",
"from": "DB",
"indice": "KSE100",
"data": [{
"stock_sector_name": "Tc",
"sector_score": "0828",
"stocks": [{
"stock_symbol": "TRG",
"stock_score": 44
},
{
"stock_symbol": "SYS",
"stock_score": 33
}
]
},
{
"stock_sector_name": "OIL",
"sector_score": "0828",
"stocks": [{
"stock_symbol": "FFS",
"stock_score": 44
},
{
"stock_symbol": "SMS",
"stock_score": 33
}
]
},
]
}
const data2 = {
"name": "KSE100",
"children": [{
"name": "A",
'points': -9,
"children": [{
"stock_title": "A",
"value": 12,
},
{
"stock_title": "B",
"value": 4,
},
]
},
{
"name": "B",
'points': 20,
"children": [{
"stock_title": "A",
"value": 12,
},
{
"name": "B",
"value": 4,
},
]
},
]
}
//stock_sector_name = name
//sector_score = value
//stocks = children
//stock_symbol = stock_title
//stock_score = value
const keys = {
stock_sector_name: "name",
sector_score: "points",
stocks: "children",
stock_symbol: "stock_title",
stock_score: "value",
indice: "name",
//data: "children"
}
const rename = (value) => {
if (!value || typeof value !== 'object') return value;
if (Array.isArray(value)) return value.map(rename);
return Object.fromEntries(Object
.entries(value)
.map(([k, v]) => [keys[k] || k, rename(v)])
);
}
renamedObj = rename(data);
console.log(renamedObj);

How to parse a JSON (Google Analytics API 4)

I have an API response in form of JSON.
"reports": [
{
"columnHeader": {
"dimensions": [
"ga:date"
],
"metricHeader": {
"metricHeaderEntries": [
{
"name": "ga:sessions",
"type": "INTEGER"
},
{
"name": "ga:users",
"type": "INTEGER"
}
]
}
},
"data": {
"rows": [
{
"dimensions": [
"20210623"
],
"metrics": [
{
"values": [
"13",
"13"
]
}
]
},
{
"dimensions": [
"20210624"
],
"metrics": [
{
"values": [
"18",
"16"
]
}
]
}
]}}]}
I need to get each metric (metricHeaderEntries) with its values in a separate Object, which is therefore is in an array "dataTracesAll".
//Example of the construction
//dataTracesAll is an array, containing objects with key "trace" + int
dataTracesAll['trace' + (i+1)] = {
name: metricsTitles[i].name, //metric title "sessions"
x: dimensions, //list of dimensions ["20210623", "20210624"]
y: dataClear //list of metrics for each metrics is separate ["13", "18"]
}
//The full code:
var titles = [];
var dataTracesAll = [];
//raw data
for (var i=0; i < data.reports.length; i++) {
//get titles
var metricsTitles = data.reports[i].columnHeader.metricHeader.metricHeaderEntries;
metricsTitles.forEach(function(title) {
titles.push(title.name.split("ga:")[1]);
});
//values and dates raw
var dimensions = [];
var dataClear = [];
var values = data.reports[i].data.rows;
//get dates and values
values.forEach(function(val) {
dimensions.push(val.dimensions[0]);
dataClear.push(val.metrics[0].values[0]); //only the first array value is added
});
//clear values
console.log(values);
//constuct array with values
dataTracesAll['trace' + (i+1)] = {
name: metricsTitles[i].name,
x: dimensions,
y: dataClear
}
}
Result of the code:
The problem is that it adds only the first value of the metrics value array and I cannot get how to parse everything, so there is actually 2 traces.
My ideal result is:
dataTracesAll = [
trace1: {
name: "ga:sessions",
x: ['20210623', '20210624']
y: ['13', '18']
},
trace2: {
name: "ga:users",
x: ['20210623', '20210624']
y: ['13', '16']
}
];
Try this:
var data = {"reports": [
{
"columnHeader": {
"dimensions": [
"ga:date"
],
"metricHeader": {
"metricHeaderEntries": [
{
"name": "ga:sessions",
"type": "INTEGER"
},
{
"name": "ga:users",
"type": "INTEGER"
}
]
}
},
"data": {
"rows": [
{
"dimensions": [
"20210623"
],
"metrics": [
{
"values": [
"13",
"13"
]
}
]
},
{
"dimensions": [
"20210624"
],
"metrics": [
{
"values": [
"18",
"16"
]
}
]
}
]}}]};
var titles = [];
var dataTracesAll = [];
var length = data.reports[0].data.rows[0].metrics[0].values.length;
//raw data
for (var i=0; i < length; i++) {
//get titles
var metricsTitles = data.reports[0].columnHeader.metricHeader.metricHeaderEntries;
metricsTitles.forEach(function(title) {
titles.push(title.name.split("ga:")[1]);
});
//values and dates raw
var dimensions = [];
var dataClear = [];
var values = data.reports[0].data.rows;
//get dates and values
values.forEach(function(val) {
dimensions.push(val.dimensions[0]);
dataClear.push(val.metrics[0].values[i]);
});
//constuct array with values
dataTracesAll.push({});
dataTracesAll[i]['trace' + (i+1)] = {
name: metricsTitles[i].name,
x: dimensions,
y: dataClear
}
}
console.log(dataTracesAll);
Edit: The result was supposed to be an array, so I changed the code accordingly.
I have updated you logic to make it fit for your requirement. Hope this will work.
const data =
{
"reports": [
{
"columnHeader": {
"dimensions": [
"ga:date"
],
"metricHeader": {
"metricHeaderEntries": [
{
"name": "ga:sessions",
"type": "INTEGER"
},
{
"name": "ga:users",
"type": "INTEGER"
}
]
}
},
"data": {
"rows": [
{
"dimensions": [
"20210623"
],
"metrics": [
{
"values": [
"13",
"13"
]
}
]
},
{
"dimensions": [
"20210624"
],
"metrics": [
{
"values": [
"18",
"16"
]
}
]
}
]
}
}]
}
const dataTracesAll = {};
const report = data.reports[0];
for (var i = 0; i < report.data.rows.length; i++) {
dataTracesAll[`trace${i + 1}`] = {
name: report.columnHeader.metricHeader.metricHeaderEntries[i].name,
x: [],
y: [],
}
}
Object.keys(dataTracesAll).forEach((key, index) => {
for (var i = 0; i < report.data.rows.length; i++) {
dataTracesAll[key].x.push(report.data.rows[i].dimensions[0]);
dataTracesAll[key].y.push(report.data.rows[i].metrics[0].values[index]);
}
})
console.log(dataTracesAll);

How to check if array is empty or not and return value inside foreach in angular8

I have below data,
What i want to do is, i need to check values[] array in each object,
if it is empty then return true, else if values[] array has some record, it will return false.
i have created function for this, but it is reuturning false everytime.
if it is true thn i want to hide table. Table are multiple not single one, so if values arrayis empty thn only want to hide particular table.
{
"records": [
{
"context": {
"team": [
"MYTEAM-Consume-TEAM-SETUP-ADMIN"
]
},
"values": []
},
{
"context": {
"team": [
"TEAM1"
]
},
"values": [
{
"value": "red",
"label": "dd"
}
]
},
{
"context": {
"team": [
"Test"
]
},
"values": []
},
]
}
Code
hideContextTable(rows) {
const data = rows;
if (data.records) {
data.records.forEach(function (record) {
if (record.values.length === 0) {
return true;
}
});
}
return false;
}
deleteAllContextData(data) {
const tbl = this.hideContextTable(data);
console.log(tbl,"tbl");
if (tbl) {
this.showContextTables = false;
}
}
Simply check the length of returned data from filter function.
data = {
"records": [
{
"context": {
"team": [
"MYTEAM-Consume-TEAM-SETUP-ADMIN"
]
},
"values": []
},
{
"context": {
"team": [
"TEAM1"
]
},
"values": [
{
"value": "red",
"label": "dd"
}
]
},
{
"context": {
"team": [
"Test"
]
},
"values": []
},
]
};
function hideContextTable(data) {
const result = data.records.filter(record => record.values.length);
const flag = result.length ? true : false;
console.log(flag)
}
hideContextTable(data);
return in the higher order function of forEach will not cause flow to leave the hideContextTable function. You should use a variable that is accessible from outside that function and set it if the condition is met, then return that variable at the end of the function.
const rows = {
"records": [
{
"context": {
"team": [
"MYTEAM-Consume-TEAM-SETUP-ADMIN"
]
},
"values": []
},
{
"context": {
"team": [
"TEAM1"
]
},
"values": [
{
"value": "red",
"label": "dd"
}
]
},
{
"context": {
"team": [
"Test"
]
},
"values": []
},
]
}
function hideContextTable(rows) {
let isEmpty = false;
const data = rows;
if (data.records && data.records.values) {
data.records.forEach(function (record) {
if (record.values.length === 0) {
isEmpty = true;
return; // this is a higher order function
// meaning: it won't leave the context of hideContextTable
}
});
}
return isEmpty;
}
const test = hideContextTable(rows);
console.log(test);

Reassigning from JS Object A property value to another

I'm trying to assign prices to my items from a JSON A to JSON B, managed to get the prices and reassign it to the property but not to the whole object.
here's a snippet of my code, which gets the prices from the first Object and reassigning it to TotalOrignialValue however how can I push it back to the newJson object?
Is there a more pleasing way of achieving this?
// Code goes here
var items = {
"TransactionLine": [
{
"Product": {
"Id": null,
"Codes": [
"1112"
],
"Sku": null
},
"TotalValue": 2.35,
},
{
"Product": {
"Id": null,
"Codes": [
"1113"
],
"Sku": null
},
"TotalValue": 2.15,
}
],
"CustomData": {}
};
var itemPrice = [];
for (var i = 0; i < items.TransactionLine.length; i++) {
var el = items.TransactionLine[i];
itemPrice.push(el.TotalValue);
console.log(el.TotalValue);
}
var newJson = {
"OrderLines": [
{
"Product": {
"Id": 9,
"Codes": [
"1113"
],
"Sku": "CS1113"
},
"TotalOriginalValue": 0, // asign the price here
},
{
"Product": {
"Id": 21,
"Codes": [
"1112"
],
"Sku": "CS1112"
},
"TotalOriginalValue": 0, // asign the price here
}
]
};
var newPrice = [];
for (var x = 0; x < newJson.OrderLines.length; x++) {
var xd = newJson.OrderLines[x].TotalOriginalValue;
xd = itemPrice[x];
newjson = {
"TotalOriginalValue": xd
};
newPrice.push(newjson);
}
console.log('newJSON >> ', newPrice);
Using Lodash makes your life so much easier that does what you need using lodash there is probably an even more succinct way of doing it with it.
var items = {
"TransactionLine": [
{
"Product": {
"Id": null,
"Codes": [
"1112"
],
"Sku": null
},
"TotalValue": 2.35,
},
{
"Product": {
"Id": null,
"Codes": [
"1113"
],
"Sku": null
},
"TotalValue": 2.15,
}
],
"CustomData": {}
};
var newJson = {
"OrderLines": [
{
"Product": {
"Id": 9,
"Codes": [
"1113"
],
"Sku": "CS1113"
},
"TotalOriginalValue": 0, // asign the price here
},
{
"Product": {
"Id": 21,
"Codes": [
"1112"
],
"Sku": "CS1112"
},
"TotalOriginalValue": 0, // asign the price here
}
]
};
var test = _.map(items.TransactionLine, (item,index) => {
return _.set(newJson.OrderLines[index], 'TotalOriginalValue', item.TotalValue)
})
console.log(test)
https://jsfiddle.net/k6vdyhx7/124/
Iterate over OrderLines key value, which is an array, then replace every TotalOriginalValue value with responding value from the items.TransactionLine array.
var items = {TransactionLine:[{Product:{Id:null,Codes:["1112"],Sku:null},TotalValue:2.35},{Product:{Id:null,Codes:["1113"],Sku:null},TotalValue:2.15}],CustomData:{}},
newJson = {OrderLines:[{Product:{Id:9,Codes:["1113"],Sku:"CS1113"},TotalOriginalValue:0},{Product:{Id:21,Codes:["1112"],Sku:"CS1112"},TotalOriginalValue:0}]};
newJson.OrderLines.forEach((v,i) => v.TotalOriginalValue = items.TransactionLine[i].TotalValue);
console.log(newJson);
it looks like your only connection from JSON A to JSON B is the codes array on the items.
You could loop over entries in JSON a, find the corresponding item in JSON B by checking the codes values, and assign the values directly on JSON B entries
var items = {
"TransactionLine": [
{
"Product": {
"Id": null,
"Codes": [
"1112"
],
"Sku": null
},
"TotalValue": 2.35,
},
{
"Product": {
"Id": null,
"Codes": [
"1113"
],
"Sku": null
},
"TotalValue": 2.15,
}
],
"CustomData": {}
};
var newJson = {
"OrderLines": [
{
"Product": {
"Id": 9,
"Codes": [
"1113"
],
"Sku": "CS1113"
},
"TotalOriginalValue": 0, // asign the price here
},
{
"Product": {
"Id": 21,
"Codes": [
"1112"
],
"Sku": "CS1112"
},
"TotalOriginalValue": 0, // asign the price here
}
]
};
items.TransactionLine.forEach(item=>{
var match = newJson.OrderLines.find(entry=>entry.Product.Codes[0] === item.Product.Codes[0]);
if (!match) {
return;
}
match.TotalOriginalValue = item.TotalValue;
});
console.log(newJson);
This will also cut out the use of the array and a loop through the items JSON.
On a list of 2 its not so bad, but add a few hundred/thousand and it will become noticeable.

Categories