Parsing JSON into Google spreadsheet (Apps Script) - javascript

I have a download in JSON format that I get through the API.
Example:
{
"Employees": [
{
"User": {
"UserId": "4d132227-ea5c-4e57-b105-2f8b97872545",
"Login": "test#gmail.com",
"FullName": {
"LastName": "Фамилия",
"FirstName": "Имя",
"MiddleName": "Отчество"
},
"IsRegistered": true
},
"Permissions": {
"UserDepartmentId": "b5072e57-1e96-490b-ae03-2fd52ef84a3a",
"IsAdministrator": false,
"DocumentAccessLevel": "SelectedDepartments",
"SelectedDepartmentIds": [
"b5072e57-1e96-490b-ae03-2fd52ef84a3a",
"cd2e04dc-8d3f-4d63-88fd-f900c496e146",
"36e4434b-519d-4e40-9253-3464c10ed83e"
],
"Actions": [
{
"Name": "CreateDocuments",
"IsAllowed": true
},
{
"Name": "DeleteRestoreDocuments",
"IsAllowed": true
},
{
"Name": "SignDocuments",
"IsAllowed": true
},
{
"Name": "AddResolutions",
"IsAllowed": true
},
{
"Name": "RequestResolutions",
"IsAllowed": true
},
{
"Name": "ManageCounteragents",
"IsAllowed": false
}
],
"AuthorizationPermission": {
"IsBlocked": false
}
},
"Position": "Специалист по снабжению",
"CanBeInvitedForChat": true,
"CreationTimestamp": {
"Ticks": 637284074150000000
}
}
],
"TotalCount": 214
}
An example of what should happen:
enter image description here
The ratio of the JSON list of employees with columns in the table:
A: "User": {"UserId"} - Employee ID
B: "User": {""FullName""} - FULL NAME
C: "Position" - Position
D: "User": {"Login"} - Mail
E: "User": {"IsRegistered"} - Login activated?
F: "Permissions": {"IsAdministrator"} - Administrator?
G: "Permissions": {"Actions": [{"Name": "SignDocuments","isAllowed": true} - Can sign documents
H: "Permissions": {"Actions": [{"Name": "AddResolutions","isAllowed": true} - Can coordinate documents
I: "Permissions": {"Actions": [{"Name": "RequestResolutions","isAllowed": true} - Can request document approval
J: "Permissions": {"Actions": [{"Name": "CreateDocuments","isAllowed": true} - Can create documents and work with drafts
K: "Permissions": {"Actions": [{"Name": "DeleteRestoreDocuments","isAllowed": true} - Can delete documents and drafts, restore documents
L: "Permissions": {"Actions": [{"Name": "ManageCounteragents","isAllowed": true} - Can work with a list of counterparties
How can I convert JSON to a Google spreadsheet for 300+ rows? At the moment I only have a request to the API. The response is JSON. What are my next steps?
function GetEmployees(){
var DdocAuthKey = GetAuthToken()
for (let i = 0; i < boxId.length; i++) {
let url = `https://diadoc-api.kontur.ru/GetEmployees?boxId=`+ boxId[i]
let options =
{
method: "GET",
contentType: 'application/json',
headers: {authorization: "DiadocAuth ddauth_api_client_id=" + DdocAPIkey + `,ddauth_token=` + DdocAuthKey}
}
var json = UrlFetchApp.fetch(url, options)
var obj = JSON.parse(json)
printValues(obj);enter code here
}
}
function printValues(obj) {
for(var k in obj) {
if(obj[k] instanceof Object) {
printValues(obj[k]);
} else {
return obj[k] + "<br>"
}
}
}

This is the final version of the code. I hope this will help developers on JS and Apps Script when working with the Diadoc API.
Due to the fact that I have 3 organizations, I need to do an additional cycle:
for (let i = 0; i < boxId.length; i++)
If necessary, this cycle can be removed.
function GetEmployees() {
clearOrgSheets()
var DdocAuthKey = GetAuthToken()
let options =
{
method: "GET",
contentType: 'application/json',
headers: {authorization: "DiadocAuth ddauth_api_client_id=" + DdocAPIkey + `,ddauth_token=` + DdocAuthKey}
}
for (let i = 0; i < boxId.length; i++) {
let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SheetNames[i])
let pageNum = 1
do {
let url = `https://diadoc-api.kontur.ru/GetEmployees?boxId=`+ boxId[i] + `&page=` + pageNum + `&count=50`
pageNum++
var obj = JSON.parse(UrlFetchApp.fetch(url, options))
var table = []; // it will be the 2d array
for (var employee of obj.Employees) {
var {LastName, FirstName, MiddleName} = employee.User.FullName;
var name = [LastName, FirstName, MiddleName].join(' ').trim();
var actions = {};
employee.Permissions.Actions.forEach(a => actions[a.Name] = a.IsAllowed);
var row =
[
employee.User.UserId,
name,
employee.Position,
employee.User.Login,
employee.User.IsRegistered,
employee.Permissions.IsAdministrator,
actions.SignDocuments, // Can sign documents
actions.AddResolutions, // Can coordinate documents
actions.RequestResolutions, // Can request document approval
actions.CreateDocuments, // Can create documents and work with drafts
actions.DeleteRestoreDocuments, // Can delete documents and drafts, restore documents
actions.ManageCounteragents, // Can work with a list of counterparties
];
table.push(row);
}
let lastRow = sheet.getLastRow() + 1
try{
let range = sheet.getRange(lastRow, 1, table.length, table[0].length )
range.setValues(table);
} catch (err){
break
}
} while (obj.Employees.length > 0);
}
}

Try this:
function myFunction() {
// here is your object (parsed json)
var obj = {
"Employees": [
{
"User": {
"UserId": "4d132227-ea5c-4e57-b105-2f8b97872545",
"Login": "test#gmail.com",
"FullName": {
"LastName": "Фамилия",
"FirstName": "Имя",
"MiddleName": "Отчество"
},
"IsRegistered": true
},
"Permissions": {
"UserDepartmentId": "b5072e57-1e96-490b-ae03-2fd52ef84a3a",
"IsAdministrator": false,
"DocumentAccessLevel": "SelectedDepartments",
"SelectedDepartmentIds": [ "b5072e57", "cd2e04dc", "36e4434b" ],
"Actions": [
{ "Name": "CreateDocuments", "IsAllowed": true },
{ "Name": "DeleteRestoreDocuments", "IsAllowed": true },
{ "Name": "SignDocuments", "IsAllowed": true },
{ "Name": "AddResolutions", "IsAllowed": true },
{ "Name": "RequestResolutions", "IsAllowed": true },
{ "Name": "ManageCounteragents", "IsAllowed": false }
],
"AuthorizationPermission": { "IsBlocked": false }
},
"Position": "Специалист по снабжению",
"CanBeInvitedForChat": true,
"CreationTimestamp": { "Ticks": 637284074150000000 }
}
],
"TotalCount": 214
};
var table = []; // it will be the 2d array
for (var employee of obj.Employees) {
var {LastName, FirstName, MiddleName} = employee.User.FullName;
var name = [LastName, FirstName, MiddleName].join(' ');
var actions = {};
employee.Permissions.Actions.forEach(a => actions[a.Name] = a.IsAllowed);
var row = [
employee.User.UserId,
name,
employee.Position,
employee.User.Login,
employee.User.IsRegistered,
employee.Permissions.IsAdministrator,
actions.SignDocuments, // Can sign documents
actions.AddResolutions, // Can coordinate documents
actions.RequestResolutions, // Can request document approval
actions.CreateDocuments, // Can create documents and work with drafts
actions.DeleteRestoreDocuments, // Can delete documents and drafts, restore documents
actions.ManageCounteragents, // Can work with a list of counterparties
];
table.push(row); // add the row to the 2d array
}
// put the 2d array on the sheet
SpreadsheetApp.getActiveSheet()
.getRange(2,1,table.length,table[0].length)
.setValues(table);
}
Let me know if it works.

Related

How to add external data to javascript for jquery auto complete

I'm trying to make a auto complete search bar using jquery autocomplete. The thing is I need to display Json data from an external site into my search bar.
Whenever I try to put the data as such from json into the script, it's working. But when I refer external url it refuses to work.
I tried implementing all json data into my script. But it takes so long to process as there will be more than 40000+ lines in my html page.
The Json link for the data which I have to display is here
<script>
$('#id_ticker').autocomplete({
source: function(request, response) {
var data = {
"success": true,
"data": [
{
"symbol": "AACG",
"name": "ATA Creativity Global American Depositary Shares",
"lastsale": "$2.19",
"netchange": "-0.45",
"pctchange": "-17.045%",
"volume": "1408435",
"marketCap": "68715455.00",
"country": "China",
"ipoyear": "",
"industry": "Service to the Health Industry",
"sector": "Miscellaneous",
"url": "/market-activity/stocks/aacg"
},
{
"symbol": "AACI",
"name": "Armada Acquisition Corp. I Common Stock",
"lastsale": "$9.88",
"netchange": "0.01",
"pctchange": "0.101%",
"volume": "8345",
"marketCap": "204609860.00",
"country": "United States",
"ipoyear": "2021",
"industry": "",
"sector": "",
"url": "/market-activity/stocks/aaci"
}],
"additional_data": {
"pagination": {
"start": 0,
"limit": 5,
"more_items_in_collection": true,
"next_start": 5
}
}
};
var datamap = data.data.map(function(i) {
return {
label: i.symbol + ' - ' + i.name.split(' ').slice(0, 2).join(' '),
value: i.symbol,
desc: i.title
}
});
var key = request.term;
datamap = datamap.filter(function(i) {
return i.label.toLowerCase().indexOf(key.toLowerCase()) >= 0;
});
response(datamap);
},
minLength: 1,
delay: 500
});
</script>
The above code works and the below code doesn't.
<script>
$('#id_ticker').autocomplete({
source: function(request, response) {
var data = {
"success": true,
"data": ["https://raw.githubusercontent.com/rreichel3/US-Stock-Symbols/main/nyse/nyse_full_tickers.json"
],
"additional_data": {
"pagination": {
"start": 0,
"limit": 5,
"more_items_in_collection": true,
"next_start": 5
}
}
};
var datamap = data.data.map(function(i) {
return {
label: i.symbol + ' - ' + i.name.split(' ').slice(0, 2).join(' '),
value: i.symbol,
desc: i.title
}
});
var key = request.term;
datamap = datamap.filter(function(i) {
return i.label.toLowerCase().indexOf(key.toLowerCase()) >= 0;
});
response(datamap);
},
minLength: 1,
delay: 500
});
</script>
Looking for a solution to add this and also for a solution to reduce the json key pair with only "symbol" and "name" from each corresponding data in the link.
Try this:
function toAutocomplete(dt, keyvar){
let rli = [];
for (let i = 0; i < dt.length; i++) rli.push(dt[i][keyvar]);
return rli;
}
function inArrayAutocompleteSelected(key, array_autocomplete, array_master){
let x = array_master[$.inArray(key, array_autocomplete)];
return x;
}
$('#id_ticker').autocomplete({ source: [], minLength: 1 });
// $('#id_ticker').autocomplete("disable");
let url = 'https://raw.githubusercontent.com/rreichel3/US-Stock-Symbols/main/nyse/nyse_full_tickers.json';
let r = _ajax('GET', url, ''); // your ajax script
console.log(r);
let liAuto = toAutocomplete(r, 'name');
console.log(liAuto);
$('#id_ticker').autocomplete("option", "source", liAuto );
// $('#id_ticker').autocomplete("enable");
$("#id_ticker").autocomplete({
select: function( event, ui ) {
console.log(ui, ui.item);
getData = inArrayAutocompleteSelected(ui.item.value, liAuto, r);
console.log(getData);
}
});

How parse JSON with complex nesting and unnamed array?

I am trying to figure out how to parse the JSON response I receive when I make a call to a specific database (JSON response shown below) using vanilla javascript - and so far I have not had any luck. I am placing an API call to the Quickbase database and they have a standard formatting for their JSON response. The API i am calling can be found at this link: https://developer.quickbase.com/operation/runQuery.
Here is what a response from the API call looks like
{
"data": [
{
"6": {
"value": 11.0
},
"69": {
"value": "A"
},
"70": {
"value": "B"
}
},
{
"6": {
"value": 11.0
},
"69": {
"value": "C"
},
"70": {
"value": "D"
}
}
],
"fields": [
{
"id": 6,
"label": "Related Invoice",
"type": "numeric"
},
{
"id": 69,
"label": "TEST1",
"type": "text"
},
{
"id": 70,
"label": "TEST2",
"type": "text"
}
],
"metadata": {
"numFields": 3,
"numRecords": 2,
"skip": 0,
"totalRecords": 2
}
}
And this is what I want to parse it into (do NOT need to omit the JSON not shown here - I just did that for clarity)
{
"data": [
{
"Related Invoice":11.0,
"TEST1":"A",
"TEST2":"B"
},
{
"Related Invoice":11.0,
"TEST1":"C",
"TEST2":"D"
}
]
}
Below is the full javascript code i am using
let headers = {
'QB-Realm-Hostname': 'XXXXXX',
'User-Agent': 'Invoice',
'Authorization': 'XXXXXX',
'Content-Type': 'application/json'
}
let body =
{
"from": "bq2paydp2",
"select": [
6,
69,
70
],
"where": "{6.EX.11}",
"sortBy": [
{
"fieldId": 6,
"order": "ASC"
},
{
"fieldId": 69,
"order": "ASC"
}
]
}
const xmlHttp = new XMLHttpRequest();
xmlHttp.open('POST', 'https://api.quickbase.com/v1/records/query', true);
for (const key in headers) {
xmlHttp.setRequestHeader(key, headers[key]);
}
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState === XMLHttpRequest.DONE) {
console.log(xmlHttp.responseText);
let line_items = JSON.parse(this.responseText, dataReviver);
console.log(line_items);
//function dataReviver (key, value) {
//if (key = 6)
// {
// var newHeaderName = 99;
// return newHeaderName;
// }
//
// return value;
//}
//document.getElementById('abc').innerHTML = line_items.data[0][6].value;
function generateTableHead(table,tableData) {
let thead = table.createTHead();
let row = thead.insertRow();
for (let key of tableData) {
let th = document.createElement("th");
let text = document.createTextNode(key);
th.appendChild(text);
row.appendChild(th);
}
};
function generateTable(table, tableData) {
for (let element of tableData) {
let row = table.insertRow();
for (key in element) {
let cell = row.insertCell();
let text = document.createTextNode(element[key]);
cell.appendChild(text);
}
}
};
let table = document.querySelector("table");
let tableData = Object.keys(line_items.data[0]);
generateTableHead(table, tableData);
generateTable(table, line_items.data);
}
};
xmlHttp.send(JSON.stringify(body));
This is what I am trying to achieve
|-----------------------------------------|
| Count | Related Invoice | TEST1 | TEST2 |
|-------|-----------------|-------|-------|
| 1 | 11.0 | A | B |
|-------|-----------------|-------|-------|
| 2 | 11.0 | C | D |
|-----------------------------------------|
I need to accomplish 3 things:
#1 Rename "6", "69 and "70" to the corresponding fields.label ( "Related Invoice", "TEST1" and "TEST2" ).
#2 Take the value of the objects nested under the objects shown above in #1 ( 11.0, "A", "B", ... ) and set them as the value of the objects shown in #1 above. This would, for example, make 6 (Related Invoice) the key and 11.0 the value.
#3 I ultimately want to display this in a table on a webpage. the html and css I can handle its the Javascript and JSON that I am not that great with.
If you need me to clarify anymore information please let me know.
To transform the data in the way you're looking, you'll need to loop over the data key in the object and create a new array based on the result of the loop.
A way to do this is with Array.prototype.map(). With this you can loop over each item in the array and return a new value.
In this map loop you are looping over each item in the data array. For each item you'll want to get the id and label from the fields array and use that array to create a new object. To create a new object within in a loop, you could use the Array.prototype.reduce() method.
So in this case you'll have a nested loop. The inner loop will loop over the fields array and uses the id to get the correct value from data array. It then returns an object with the label and the value set like you requested. The surrounding map method will then return a new array with objects. Tadaa, magic!
const response = {
"data": [{
"6": {
"value": 11.0
},
"69": {
"value": "A"
},
"70": {
"value": "B"
}
},
{
"6": {
"value": 11.0
},
"69": {
"value": "C"
},
"70": {
"value": "D"
}
}
],
"fields": [{
"id": 6,
"label": "Related Invoice",
"type": "numeric"
},
{
"id": 69,
"label": "TEST1",
"type": "text"
},
{
"id": 70,
"label": "TEST2",
"type": "text"
}
],
"metadata": {
"numFields": 3,
"numRecords": 2,
"skip": 0,
"totalRecords": 2
}
};
const transformResponseData = (response) => {
const { data, fields } = response;
// Return a new array with objects based on the values
// of the data and fields arrays.
const revivedData = data.map(entry =>
fields.reduce((object, { id, label }) => {
object[label] = entry[id].value;
return object;
}, {})
);
// Combine the original object with the new data key.
return {
...response,
data: revivedData
};
};
const createTable = ({ data, fields }) => {
const table = document.createElement('table');
const tHead = table.createTHead();
const tBody = table.createTBody();
const tHeadRow = tHead.insertRow();
// Create the counts cell manually.
const tHeadRowCountCell = document.createElement('th');
tHeadRowCountCell.textContent = 'Count';
tHeadRow.append(tHeadRowCountCell);
// Create a head for each label in the fields array.
for (const { label } of fields) {
const tHeadRowCell = document.createElement('th');
tHeadRowCell.textContent = label;
tHeadRow.append(tHeadRowCell);
}
// Output all the values of the new data array.
for (const [index, entry] of data.entries()) {
const tBodyRow = tBody.insertRow();
// Create a new array with the index and the
// values from the object.
const values = [
index + 1,
...Object.values(entry)
];
// Loop over the combined values array.
for (const [index, value] of values.entries()) {
const tBodyCell = tBodyRow.insertCell();
tBodyCell.textContent = index === 1 ?
value.toFixed(1) :
value;
}
}
return table;
};
const data = transformResponseData(response);
const table = createTable(data);
document.body.append(table);

Deleting a key in JSON while making ajax call from javascript

I am new to java script and ajax. I have a JSON and I want to remove outputs cell in this JSON:
{
"cells": [{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "print(\"hi\")",
"execution_count": 1,
"outputs": [{
"output_type": "stream",
"text": "hi\n",
"name": "stdout"
}]
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "",
"execution_count": null,
"outputs": []
}
],
"metadata": {
"kernelspec": {
"name": "Python [Root]",
"display_name": "Python [Root]",
"language": "python"
},
"anaconda-cloud": {},
"language_info": {
"pygments_lexer": "ipython3",
"version": "3.5.0",
"codemirror_mode": {
"version": 3,
"name": "ipython"
},
"mimetype": "text/x-python",
"file_extension": ".py",
"name": "python",
"nbconvert_exporter": "python"
},
"gist": {
"id": "",
"data": {
"description": "Untitled5.ipynb",
"public": true
}
}
},
"nbformat": 4,
"nbformat_minor": 0
}
and this is my attempt on removing the outputs cell. This piece of code posts the data to above mentioned JSON:
"use strict";
function _objectWithoutProperties(obj, keys) {
var target = {};
for (var i in obj) {
if (keys.indexOf(i) >= 0) continue;
if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
target[i] = obj[i];
}
return target;
}
var outputs = data.cells;
var data_dup = _objectWithoutProperties(data, ["outputs"]);
var id_input = $('#gist_id');
var id = params.gist_it_personal_access_token !== '' ? id_input.val() : '';
var method = id ? 'PATCH' : 'POST';
// Create/edit the Gist
$.ajax({
url: 'https://api.github.com/gists' + (id ? '/' + id : ''),
type: method,
dataType: 'json',
data: JSON.stringify(data_dup),
beforeSend: add_auth_token,
success: gist_success,
error: gist_error,
complete: complete_callback
});
};
But this code doesnt work. Can some one please guide how can we directly strip a key(outputs in this case) from ajax call and post it to JSON.
This is a gist extension of jupyter notebook and I am trying to strip output while posting it to gist on github
function _objectWithoutProperties(obj, key="outputs") { obj.cells.forEach(cell=>delete(cell[key])); }
If you use ES6, you can use this syntax to remove outputs:
{
...data,
cells: data.cells.map(({ outputs, ...otherProps }) => otherProps),
}
Note: data is your complete object.

Group and count values in an array

I have an array with objects, like the following.
b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
I want to count how many issues have status close, and how many have backlog. I'd like to save the count in a new array as follows.
a = [
{Name: 'Backlog', count: 1},
{Name: 'close', count: 2}
];
I have tried the following.
b.issues.forEach(function(i) {
var statusName = i.fields.status.name;
if (statusName in a.Name) {
a.count = +1;
} else {
a.push({
Name: statusName,
count: 1
});
}
});
That however doesn't seem to be working. How should I implement this?
This is a perfect opportunity to use Array#reduce. That function will take a function that is applied to all elements of the array in order and can be used to accumulate a value. We can use it to accumulate an object with the various counts in it.
To make things easy, we track the counts in an object as simply {name: count, otherName: otherCount}. For every element, we check if we already have an entry for name. If not, create one with count 0. Otherwise, increment the count. After the reduce, we can map the array of keys, stored as keys of the object, to be in the format described in the question. See below.
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var counts = b.issues.reduce((p, c) => {
var name = c.fields.status.name;
if (!p.hasOwnProperty(name)) {
p[name] = 0;
}
p[name]++;
return p;
}, {});
console.log(counts);
var countsExtended = Object.keys(counts).map(k => {
return {name: k, count: counts[k]}; });
console.log(countsExtended);
.as-console-wrapper {
max-height: 100% !important;
}
Notes.
Array#reduce does not modify the original array.
You can easily modify the function passed to reduce to for example not distinguish between Backlog and backlog by changing
var name = c.fields.status.name;
into
var name = c.fields.status.name.toLowerCase();
for example. More advanced functionality can also easily be implemented.
Using ES6 Arrow functions you can do it with minimum syntax
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var countOfBackLog = b.issues.filter(x => {
return x.fields.status.name === "Backlog"
}).length
var countOfClose = b.issues.filter(x => {
return x.fields.status.name === "close"
}).length
a =[{Name: 'Backlog', count : countOfBackLog}, {Name: 'close', count : countOfClose}]
More about arrow functions here
You can write like this. It is dynamic.
var a = {};
for(var key in b["issues"]){
if(!a.hasOwnProperty(b["issues"][key].fields.status.name)){
a[b["issues"][key].fields.status.name] = 1;
}else{
a[b["issues"][key].fields.status.name] = a[b["issues"][key].fields.status.name]+1;
}
}
var c = [];
for(var key1 in a){
c.push({
name : key1,
count : a[key1]
});
}
Something like this should do the trick. Simply iterate over your data, keep 2 counters with the number of each type of issue, and create the data format you want in the end. Try it live on jsfiddle.
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var data = [];
for(var issue of b.issues){
var entryFound = false;
var tempObj = {
name: issue.fields.status.name,
count: 1
};
for(var item of data){
if(item.name === tempObj.name){
item.count++;
entryFound = true;
break;
}
}
if(!entryFound){
data.push(tempObj);
}
}
console.log(data);

filter result using 2 JSON

This is my saved localstorage,
[{"industry_Id":1,"merchant_id":2}]
I want to filter below result, to get HP.
{
"industries": [
{
"id": 1,
"name": "oil and gas",
"merchant": [
{
"id": 1,
"name": "ABC",
},
{
"id": 2,
"name": "DEF",
},
{
"id": 3,
"name": "GHJ",
}
]
},
{
"id": 2,
"name": "IT",
"merchant": [
{
"id": 1,
"name": "Apple",
},
{
"id": 2,
"name": "HP",
},
{
"id": 3,
"name": "Google",
}
]
}
]
}
I thought of using multiple $.each but it have to iterate few times and it's quite redundant.
I would prefer using Javascript for loop, that way you can skip iterating over every object once required element is found.
Without jQuery (using for)
var i, j, merchant = null;
for(i = 0; i < data['industries'].length; i++){
if(data['industries'][i]['id'] == arg[0]['industry_Id']){
for(j = 0; j < data['industries'][i]['merchant'].length; j++){
if(data['industries'][i]['merchant'][j]['id'] == arg[0]['merchant_id']){
merchant = data['industries'][i]['merchant'][j];
break;
}
}
if(merchant !== null){ break; }
}
}
With jQuery (using $.each)
var merchant_found = null;
$.each(data['industries'], function(i, industry){
if(industry['id'] == arg[0]['industry_Id']){
$.each(industry['merchant'], function(i, merchant){
if(merchant['id'] == arg[0]['merchant_id']){
merchant_found = merchant;
}
return (!merchant_found);
});
}
return (!merchant_found);
});
var arg = [{"industry_Id":1,"merchant_id":2}];
var data = {
"industries": [
{
"id": 1,
"name": "oil and gas",
"merchant": [
{
"id": 1,
"name": "ABC",
},
{
"id": 2,
"name": "DEF",
},
{
"id": 3,
"name": "GHJ",
}
]
},
{
"id": 2,
"name": "IT",
"merchant": [
{
"id": 1,
"name": "Apple",
},
{
"id": 2,
"name": "HP",
},
{
"id": 3,
"name": "Google",
}
]
}
]
};
var i, j, merchant = null;
for(i = 0; i < data['industries'].length; i++){
if(data['industries'][i]['id'] == arg[0]['industry_Id']){
for(j = 0; j < data['industries'][i]['merchant'].length; j++){
if(data['industries'][i]['merchant'][j]['id'] == arg[0]['merchant_id']){
merchant = data['industries'][i]['merchant'][j];
break;
}
}
if(merchant !== null){ break; }
}
}
console.log(merchant);
document.writeln("<b>Without jQuery:</b><br>");
document.writeln((merchant !== null) ? "Found " + merchant['name'] : "Not found");
var merchant_found = null;
$.each(data['industries'], function(i, industry){
if(industry['id'] == arg[0]['industry_Id']){
$.each(industry['merchant'], function(i, merchant){
if(merchant['id'] == arg[0]['merchant_id']){
merchant_found = merchant;
}
return (!merchant_found);
});
}
return (!merchant_found);
});
console.log(merchant_found);
document.writeln("<br><br><b>With jQuery:</b><br>");
document.writeln((merchant_found) ? "Found " + merchant_found['name'] : "Not found");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
selectors.map(function(selector) {
return data.industries.filter(function(industry) {
return industry.id == selector.industry_Id;
})[0].merchant.filter(function(merchant) {
return merchant.id == selector.merchant_id;
})[0].name;
});
// => DEF
If you want "HP", you want industry 2, not industry 1.
.filter(...)[0] is not really optimal. You could use .find(...), but that is not yet universally supported. Or you could use plain old JavaScript and write for loops instead to make it fast. Or you could use objects with ID keys instead of arrays to make lookups faster.
When it comes into a position where collection of data is what you're processing, I suggest you to take a look at underscore.js. It's not optimal choice for the best performance but it does make you code more readable and makes more sense especially when compared with loop.
Say data is a variable which stores your JSON data.
Try this:
// Given this selector criteria
var select = [{"industry_Id":1,"merchant_id":2}];
function filterByCriteria(criteria, data){
var match = [];
_.each(criteria, function(crit){
function matchIndustry(rec){ return rec.id===crit.industry_Id }
function matchMerchant(rec){ return rec.id===crit.merchant_id }
// Filter by industry id
var industry = _.first(_.where(data.industry, matchIndustry));
// Filter by merchant id
var merchant = _.where(industry.merchant, matchMerchant);
_.each(merchant, function addToMatchResult(m){
match.push(m.name);
});
});
return match;
}
var filteredData = filterByCriteria(select, data);
From snippet above, any merchants which match the search criteria will be taken to the match list. Is it more readable to you?
Do you even need numerical id's? Gets super easy when you don't.
/*
{
"industry": {
"oil and gas":{
"merchant": {
"ABC": {
"name": "ABC oil"
},
"DEF": {
"name": "DEF gas"
},
"GHJ" :{
"name": "GHJ oil and gas"
}
}
},
"IT": {
"merchant": {
"Apple" : {
"name": "Apple computers"
},
"HP": {
"name": "Hewlett Packard"
},
"Google": {
"name": "Google. Maw haw haw"
}
}
}
}
}
*/
var data = '{"industry": {"oil and gas":{"merchant": {"ABC": {"name": "ABC oil"},"DEF": {"name": "DEF gas"},"GHJ" :{"name": "GHJ oil and gas"}}},"IT": {"merchant": {"Apple" : {"name": "Apple computers"},"HP": {"name": "Hewlett Packard"},"Google": {"name": "Google. Maw haw haw"}}}}}';
data = JSON.parse(data);
var merchant = data.industry['IT'].merchant['HP'];
alert(merchant.name);
//console.log(merchant.name);

Categories

Resources