How to iterate through deeply nested objects inside of a JSON? - javascript

I know there are plenty of questions about iterating through JSON objects but I haven't found one that quite relates to my exact problem. This is the JSON that I'm trying to iterate through:
psinsights = {
"kind": "pagespeedonline#result",
"id": "/speed/pagespeed",
"responseCode": 200,
"title": "PageSpeed Home",
"score": 90,
"pageStats": {
"numberResources": 22,
"numberHosts": 7,
"totalRequestBytes": "2761",
"numberStaticResources": 16,
"htmlResponseBytes": "91981",
"cssResponseBytes": "37728",
"imageResponseBytes": "13909",
"javascriptResponseBytes": "247214",
"otherResponseBytes": "8804",
"numberJsResources": 6,
"numberCssResources": 2
},
"formattedResults": {
"locale": "en_US",
"ruleResults": {
"AvoidBadRequests": {
"localizedRuleName": "Avoid bad requests",
"ruleImpact": 0.0
},
"MinifyJavaScript": {
"localizedRuleName": "Minify JavaScript",
"ruleImpact": 0.1417,
"urlBlocks": [
{
"header": {
"format": "Minifying the following JavaScript resources could reduce their size by $1 ($2% reduction).",
"args": [
{
"type": "BYTES",
"value": "1.3KiB"
},
{
"type": "INT_LITERAL",
"value": "0"
}
]
},
"urls": [
{
"result": {
"format": "Minifying $1 could save $2 ($3% reduction).",
"args": [
{
"type": "URL",
"value": "http://code.google.com/js/codesite_tail.pack.04102009.js"
},
{
"type": "BYTES",
"value": "717B"
},
{
"type": "INT_LITERAL",
"value": "1"
}
]
}
},
{
"result": {
"format": "Minifying $1 could save $2 ($3% reduction).",
"args": [
{
"type": "URL",
"value": "http://www.gmodules.com/ig/proxy?url\u003dhttp%3A%2F%2Fjqueryjs.googlecode.com%2Ffiles%2Fjquery-1.2.6.min.js"
},
{
"type": "BYTES",
"value": "258B"
},
{
"type": "INT_LITERAL",
"value": "0"
}
]
}
}
]
}
]
},
"SpriteImages": {
"localizedRuleName": "Combine images into CSS sprites",
"ruleImpact": 0.0
}
}
},
"version": {
"major": 1,
"minor": 11
}
};
Now, I'm trying to write a function that iterates through all of the ruleResults objects and returns an array of the localizedRuleName properties. According to the JSON, ruleResults has three member objects (AvoidBadRequests, MinifyJavaScript, and SpriteImages). Each of these has a localizedRuleName property I'm trying to access, but when I print out my array, it's blank. Here's how I've written my function:
function ruleList(results) {
var ruleArray = [];
for(var ruleName in results.formattedResults.ruleResults){
ruleArray[counter] = results.formattedResults.ruleResults[ruleName].localizedRuleName;
}
return ruleArray;
}
console.log(ruleList(psinsights));
Can you guys help me get on the right track? I used basically this same method to iterate through the pageStats of the JSON and it worked perfectly. I'm not sure why I can't get it to work with these deeper nested objects and properties.

your problem is not your iteration, but your undefined variable "counter".
Instead of using a counter can use the "push" function:
function ruleList(results) {
var ruleArray = [];
for(var ruleName in results.formattedResults.ruleResults){
ruleArray.push(results.formattedResults.ruleResults[ruleName].localizedRuleName);
}
return ruleArray;
}
fiddle: https://jsfiddle.net/fo9h56gh/
Hope this helps.

you're probably getting a javascript error since counter is not defined. you can try this:
function ruleList(results) {
var ruleArray = [];
var counter = 0;
for(var ruleName in results.formattedResults.ruleResults){
ruleArray[counter] = results.formattedResults.ruleResults[ruleName].localizedRuleName;
counter++;
}
return ruleArray;
}

Related

Use data from Quandl API to show in Appsmith table widget

I am building a web-app and want to connect data from Quandl through its JSON API.
However, the JSON I get from quandl has the column names separate from the data itself, check below:
{
"datatable": {
"data": [
[
"AAPL",
"MRY",
"2020-12-31",
"2020-09-26",
"2020-09-26",
"2021-07-28",
-406000000,
323888000000,
325562500000
]
],
]
],
"columns": [
{
"name": "ticker",
"type": "String"
},
{
"name": "dimension",
"type": "String"
},
{
"name": "calendardate",
"type": "Date"
},
{
"name": "datekey",
"type": "Date"
},
{
"name": "reportperiod",
"type": "Date"
},
{
"name": "lastupdated",
"type": "Date"
},
{
"name": "accoci",
"type": "Integer"
},
{
"name": "assets",
"type": "Integer"
},
{
"name": "assetsavg",
"type": "Integer"
}
]
},
"meta": {
"next_cursor_id": null
}
}
When I use this data in Appsmith, it can not infer the column names. Is there a simple javascript code to combine the column names with the data? Thank you!
This is possible with a simple JS snippet, Now my code written is not that great but will work in this case (Can be optimised)
{{
function() {
let tableData = [];
_.map(_d.datatable.data, (v, i) => {
let set = {}
_.map(v, (x, k) => {
var obj = {[_d.datatable.columns[k].name]: x}
set = {...set, ...obj}
})
tableData.push(set)
})
}()
}}
In the above snippet _d is the data which you receive, We map the array value index with the given column index and create a new object out of it, Also since this is a multiline JS code, In Appsmith we need to write this inside an IIFE like above.

Look up value from array in another array, and then match a second value Google Apps Script Javascript JSON API

I'm importing data from my crm Pipedrive into Google sheets using Google Apps Script. This is part of a larger process but I'm at an impasse with this section of the script. I need to return a value by matching two parts of one array to another array.
First I pull all deal fields, which returns custom field keys and their id/label pairs. Here's a simplified output example:
{
"success": true,
"data": [
{
"id": 12500,
"key": "c4ecbe01c34994ede3a50c0f8",
"name": "Lead Type",
"options": [
{
"label": "Expired",
"id": 28
},
{
"label": "Sale",
"id": 29
},
{
"label": "Rent",
"id": 30
},
{
"label": "Other",
"id": 31
}
],
"mandatory_flag": false
}
]
}
Then I have separate info from a specific deal that includes an id. I need to match the below id 28 to the above array and return the label Expired:
var leadType = dealresponse.data["c4ecbe01c34994ede3a50c0f8"];
which returns 28
I don't know what '28' means so that's why I need to match it to the label Expired.
The dealFields array is long, maybe 50 or 100 of the above array objects. And there are around 10 custom deal field keys where I will have to return the label base on matching the key and id. I think I have to loop each key and id to return the label. But not sure of the optimum way to do this and save on processing power.
I tried:
for (var i in dealFieldsresponse) {
if (dealFieldsresponse[i].data.key == "c4ecbe01c34994ede3a50c0f8") {
for (var j in dealFieldsresponse[j]) {
if (dealFieldsresponse[j].id == "28") {
Logger.log(dealFieldsresponse[j].label);
}
}
}
}
It's not working. I'm new at javascript and programming in general so this is my best guess and I appreciate any insights.
Edit: here's a bigger chunk of code that I have to work with:
// Get deal fields data
var dealFieldsurl = URL +'/v1/dealFields?api_token='+ API_TOKEN;
var options = {
"method": "get",
"contentType": "application/json",
};
var dealFieldsresponse = UrlFetchApp.fetch(dealFieldsurl, options);
dealFieldsresponse = JSON.parse(dealFieldsresponse.getContentText());
// Get deal data
var dealurl = URL +'/v1/deals/' + dealId + '?api_token='+ API_TOKEN;
var options = {
"method": "get",
"contentType": "application/json",
};
var dealresponse = UrlFetchApp.fetch(dealurl, options);
dealresponse = JSON.parse(dealresponse.getContentText());
var propertyAddress = dealresponse.data["9bd1d8c4f07f5795fd8bffb16f3b63c6547d7d3a"];
var leadType = dealresponse.data["c4ecbe01c3494d1be52432f4a3194ede3a50c0f8"];
var dealType = dealresponse.data["a4269fb4730cf7fd1787752be94eacbc4b0de24e"];
var dealSource = dealresponse.data["d76fa2d6f8454a51f7d64d981cd9320877bc2ea0"];
var marketingFor = dealresponse.data["58cb55090b55652b7f89a8b44074682d874c548a"];
var dateListedOnMarket = dealresponse.data["aa49c7b95a7d151bec4c2d936f6ab40d0caea43c"];
var dateTakenOffMarket = dealresponse.data["660c1250b0a641a10ff9121c2df124ff89c13052"];
var askingPrice = dealresponse.data["1de94dbf589fda7a3a3248662cd24f03d512a961"];
And the dealFieldsresponse variable stores an array with many objects containing arrays. Here are two primary objects, as you can see each has a key and then options. I need to match the key and then find the id within options for each key
{
"id": 12500,
"key": "c4ecbe01c3494d1be52432f4a3194ede3a50c0f8",
"name": "Lead Type",
"order_nr": 64,
"field_type": "set",
"add_time": "2020-08-20 19:33:22",
"update_time": "2020-08-20 19:33:22",
"last_updated_by_user_id": 11678191,
"active_flag": true,
"edit_flag": true,
"index_visible_flag": true,
"details_visible_flag": true,
"add_visible_flag": true,
"important_flag": true,
"bulk_edit_allowed": true,
"searchable_flag": false,
"filtering_allowed": true,
"sortable_flag": true,
"options": [
{
"label": "Expired",
"id": 28
},
{
"label": "Sale",
"id": 29
},
{
"label": "Rent",
"id": 30
},
{
"label": "Other",
"id": 31
}
],
"mandatory_flag": false
},
{
"id": 12502,
"key": "a4269fb4730cf7fd1787752be94eacbc4b0de24e",
"name": "Deal Type",
"order_nr": 65,
"field_type": "set",
"add_time": "2020-08-20 19:57:12",
"update_time": "2020-08-20 19:57:12",
"last_updated_by_user_id": 11678191,
"active_flag": true,
"edit_flag": true,
"index_visible_flag": true,
"details_visible_flag": true,
"add_visible_flag": true,
"important_flag": true,
"bulk_edit_allowed": true,
"searchable_flag": false,
"filtering_allowed": true,
"sortable_flag": true,
"options": [
{
"label": "Lease",
"id": 37
},
{
"label": "Financing",
"id": 38
},
{
"label": "Assign",
"id": 39
},
{
"label": "ST",
"id": 40
},
{
"label": "Other (see notes)",
"id": 41
}
],
"mandatory_flag": false
},
Edit 2: how do I return the labels for multiple ids?
const obj = {
"a4269fb4730cf7fd1787752be94eacbc4b0de24e": {id: 37,38}, "58cb55090b55652b7f89a8b44074682d874c548a": {id: 44,45},
"2ec54cce0d091b69b1fd1a245c7aad02b57cadb8": {id: 126},
"fab84c732295022ecd7bdf58892a62cb4d8ecf24": {id: 50,52,54},
};
For example, I'd want the first to return red, blue as a string, and the second to return green, orange as a string. Assuming the labels that match the ids are colors. The third one only has one id, but the fourth one has three. How do I account for this? And I'd like my output to be some kind of array where I can then say search key a4269fb4730cf7fd1787752be94eacbc4b0de24e and return value red, blue as a string
I believe your goal as follows.
You want to retrieve the value of label using key and id from the JSON object in your question using Google Apps Script.
As a sample situation, you want to retrieve the value of "label": "Expired" using "key": "c4ecbe01c34994ede3a50c0f8" and "id": 28.
The JSON object has the arrays of data and options. Both arrays have the several elements.
Modification points:
If dealFieldsresponse is the JSON object in your question, dealFieldsresponse.data and dealFieldsresponse.data[].options are 1 dimensional array. When you want to retrieve the value of key and id, it is required to loop those arrays.
When above points are reflected to your script, it becomes as follows.
Modified script:
const searchKey = "c4ecbe01c34994ede3a50c0f8"; // Please set the value of key.
const searchId = 28; // Please set the value of id.
const dealFieldsresponse = {
"success": true,
"data": [
{
"id": 12500,
"key": "c4ecbe01c34994ede3a50c0f8",
"name": "Lead Type",
"options": [
{
"label": "Expired",
"id": 28
},
{
"label": "FSBO",
"id": 29
},
{
"label": "FRBO",
"id": 30
},
{
"label": "Other",
"id": 31
}
],
"mandatory_flag": false
}
]
};
const data = dealFieldsresponse.data;
for (let i = 0; i < data.length; i++) {
if (data[i].key == searchKey) {
const options = data[i].options;
for (let j = 0; j < options.length; j++) {
if (options[j].id.toString() == searchId.toString()) {
// Logger.log(options[j].label);
console.log(options[j].label);
}
}
}
}
Other sample:
As other sample script, how about the following script? In this sample, the result values are put in an array.
const searchKey = "c4ecbe01c34994ede3a50c0f8"; // Please set the value of key.
const searchId = 28; // Please set the value of id.
const dealFieldsresponse = {
"success": true,
"data": [
{
"id": 12500,
"key": "c4ecbe01c34994ede3a50c0f8",
"name": "Lead Type",
"options": [
{
"label": "Expired",
"id": 28
},
{
"label": "FSBO",
"id": 29
},
{
"label": "FRBO",
"id": 30
},
{
"label": "Other",
"id": 31
}
],
"mandatory_flag": false
}
]
};
const res = dealFieldsresponse.data.reduce((ar, {key, options}) => {
if (key == searchKey) {
options.forEach(({id, label}) => {
if (id == searchId) ar.push(label);
});
}
return ar;
}, []);
console.log(res)
Added:
When you want to retrieve the multiple values using the multiple key and id, how about the following sample script? In this sample script, the key c4ecbe01c34994ede3a50c0f8 and id 28 and the key a4269fb4730cf7fd1787752be94eacbc4b0de24e and id 37 are searched and the values of label are retrieved.
const obj = {
"c4ecbe01c34994ede3a50c0f8": {id: 28},
"a4269fb4730cf7fd1787752be94eacbc4b0de24e": {id: 37}
}; // Please set the key and id you want to search.
const dealFieldsresponse = {
"success": true,
"data": [
{
"id": 12500,
"key": "c4ecbe01c34994ede3a50c0f8",
"name": "Lead Type",
"options": [
{
"label": "Expired",
"id": 28
},
{
"label": "FSBO",
"id": 29
},
{
"label": "FRBO",
"id": 30
},
{
"label": "Other",
"id": 31
}
],
"mandatory_flag": false
}
]
};
dealFieldsresponse.data.forEach(({key, options}) => {
if (obj[key]) {
options.forEach(({id, label}) => {
if (id == obj[key].id) obj[key].label = label;
});
}
});
console.log(obj)
Result:
When above script is run, the following result is obtained.
{
"c4ecbe01c34994ede3a50c0f8":{"id":28,"label":"Expired"},
"a4269fb4730cf7fd1787752be94eacbc4b0de24e":{"id":37}
}
At above sample JSON object, the label of the key c4ecbe01c34994ede3a50c0f8 and id 28 is retrieved.

cannot update an array of elements via a 2d iteration

I have two arrays of object, the first array (printerChart, around 80 elements) is made of the following type of objects:
[{
printerBrand: 'Mutoh',
printerModel: 'VJ 1204G',
headsBrand: 'Epson',
headType: '',
compatibilty: [
'EDX',
'DT8',
'DT8-Pro',
'ECH',
],
},
....
]
The second array (items, around 500 elements) is made of the following type of objects:
[
{
"customData": {
"brand": {
"value": {
"type": "string",
"content": "hp"
},
"key": "brand"
},
"printer": {
"value": {
"type": "string",
"content": "c4280"
},
"key": "printer"
}
},
"name": "DT8 XLXL",
"image": {
"id": "zLaDHrgbarhFSnXAK",
"url": "https://xxxxxxx.net/images/xxxxxx.jpg"
},
"brandId": "xxxxx",
"companyId": "xxxx",
"createdAt": "2018-03-26T14:39:47.326Z",
"updatedAt": "2018-04-09T14:31:38.169Z",
"points": 60,
"id": "dq2Zezwm4nHr8FhEN"
},
...
]
What I want to do is to iterate via the second array and, if the part of the name of an item (i.e. DT8) is included in an element of the array 'compatibility' of the first array, I would like to include a new properties to it from the element of the first array: printerBrand. I have tried but somehow the iteration doesn't take place correctly. This is what I tried:
items.forEach((item) => {
printerChart.forEach((printer) => {
if (printer.compatibilty.some(compatibleElem => (
item.name.includes(compatibleElem)))) {
item.printerBrand = printer.printerBrand;
} else {
item.printerBrand = '';
}
});
});
What am I doing wrong?
You do
items.items.forEach(...)
Shouldn't you be doing
items.forEach(...)
?
I suggest to initialize item.printerBrand with an empty string and use a nested approach of some for getting a brand and to exit the loops, if found.
This prevents to get an empty string even if there is a brand to assign.
items.forEach((item) => {
item.printerBrand = '';
printerChart.some(printer => {
if (printer.compatibilty.some(compatibleElem => item.name.includes(compatibleElem))) {
item.printerBrand = printer.printerBrand;
return true;
}
});
});

Transform nested array to D3 multiline time series

I'd like to transform a nested JSON object for a time series D3 multiline chart. I'd like to transform this:
[
{
"utc_date": "2012-12-13T00:00:00.000Z",
"data": {
"view": {
"count": 9061
},
"purchase": {
"count": 254
}
}
},
{
"utc_date": "2012-12-14T00:00:00.000Z",
"data": {
"view": {
"count": 17232
},
"purchase": {
"count": 539
}
}
},
{
"utc_date": "2012-12-15T00:00:00.000Z",
"data": {
"view": {
"count": 28783
},
"purchase": {
"count": 936
}
}
}]
to something like this (or better?)
[
{
"key": "view",
"data": [
{
"date": "2012-12-13T00:00:00.000Z",
"count": 9061
},
{
"date": "2012-12-14T00:00:00.000Z",
"count": 17232
},
{
"date": "2012-12-15T00:00:00.000Z",
"count": 28783
}
]
},
{
"key": "purchase",
"data": [
{
"date": "2012-12-13T00:00:00.000Z",
"count": 254
},
{
"date": "2012-12-14T00:00:00.000Z",
"count": 539
},
{
"date": "2012-12-15T00:00:00.000Z",
"count": 936
}
]
}
]
To be clear, "view" and "purchase" will not be known and are dynamic. So they shouldn't be hardcoded into the example.
But still wondering if there is any D3.js method or chain of methods to transform this data?
Assuming your original array is data, you could do something like this:
V=data.map(function(d){
w=d.data;
M=Array();
for (e in w) { // to loop for all parameters
M.push({"date":d.utc_date, "param":e,"count":w.view.count})
}
return M;
})
V=d3.merge(V)
V=d3.nest().key(function(d){return d.param}).entries(V);
V will hold your new data structure.
I am sure that this can be further improved.
EDIT
Perhaps you don't even need the d3.merge if you only append to another Array to begin with.
M=Array();
V=data.map(function(d){
w=d.data;
for (e in w) {
M.push({"date":d.utc_date, "param":e,"count":w.view.count})
}
})
V=d3.nest().key(function(d){return d.param}).entries(M);
I will let you experiement and see the difference in the performance and code structure.
Hope it helps
Just improving #Nikos answer below to cater for dynamic keys and, although it doesn't use a D3 method chain, this worked:
var result = [];
data.forEach(function(d) {
w = d.data;
for (var k in w) {
if (w.hasOwnProperty(k)) {
result.push({
"date":d.utc_date,
"type":k,
"count":w[k].count
});
}
}
});
JSFiddle here: http://jsfiddle.net/3umm391n/8/

Finding child object using one of its properties in JSON

I am trying to find a child object in JSON by one of its properties and add more properties to that object. I am not sure how to do this using JQuery (or regular javascript). For example: From the following JSON, I would like to find a category with id 123-1 and then add another category object as a child object. Thanks for your help.
JSON:
{
"result": {
"category":
{
"id": 123,
"name": "cat1",
"rules": [
{
"rulename": "r1",
"regex": ""
},
{
"rulename": "r2",
"regex": ""
}
],
"category":
{
"id": "123-1",
"name": "cat1-1",
"rules": [
{
"rulename": "r1-1",
"regex": ""
}
]
}
}
}
}
Javascript:
function addSubCategory(catId, anotherCatObj) {
//Step1: Find category object with catID in the existing json
//Step3: add the supplied object as a child.
}
function appendCategoryTo(categories, destinationCategoryId, newCategoryToAdd){
var success = false;
for (var i = 0; i < categories.length && !success; i++){
var category = categories[i];
if (category.id == destinationCategoryId){
category.category = category.category || [];
success = !!category.category.push(newCategoryToAdd);
} else if (category.category) {
success = appendCategoryTo(category.category, destinationCategoryId, newCategoryToAdd);
}
}
return success;
}
you have to start at the obj.result.category node in order to take advantage of the recursive ability, but you can easily wrap that method in another that makes it more polite.
but, as-is, here's an example usage:
appendCategoryTo(o.result.category, '123-1', {
id: '123-1-1',
name: 'cat-1-1-1',
rules: []
});
console.log(JSON.stringify(o));
Which adds a new category property to the nested category as an array (i assume this follows the nomenclature) then adds the element to that new array--thus giving you:
{
"result": {
"category": [
{
"id": 123,
"name": "cat1",
"rules": [
{
"rulename": "r1",
"regex": ""
},
{
"rulename": "r2",
"regex": ""
}
],
"category": [
{
"id": "123-1",
"name": "cat1-1",
"rules": [
{
"rulename": "r1-1",
"regex": ""
}
],
"category": [ // BEGIN new addition
{
"id": "123-1-1",
"name": "cat-1-1-1",
"rules": [
]
}
] // END new addition
}
]
}
]
}
}
Example to play with on jsfiddle, btw: http://jsfiddle.net/cqRzX/

Categories

Resources