Improve performance in Google App Script Search functions - javascript

I have written a script using Google App Script (in javascript) and I am looking for a way to be best optimize function that return objects, based on one or more search fields. The data is stored in a Google Sheet. The UI I have passes parameters to my function, then I iterate over a given sheet to find rows that meet a criteria, and add cells to an object, to be returned. The return could be just one object or a list of objects. For the most part, this works fine, but if I have this type of function nested in a loop it can really drag the performance. Any advise on how to improve performance would be greatly appreciated. Here is an example of my code:
function GetAllReportByOrgID_DataLayer_(org_id, reporting_periods) {
//get all reporting period for program
var rows = GetDataRows_(DATA_SPREAD_SHEET_ID, RESPONSE_PAGE);
var surveys = [];
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_org_id = row[2];
var found_is_active = row[13];
if (found_org_id == org_id && found_is_active == true ) {
var survey = {};
survey.indicator_id = row[0];
survey.program_id = row[1];
survey.org_guid = row[2];
survey.survey_response = row[3];
survey.reporting_period = row[5];
survey.reporting_period_name = GetReportingPeriodNameById_(row[5], reporting_periods);
survey.is_final_report = row[6];
survey.is_submitted = row[7];
survey.submitted_by = row[8];
survey.submitted_by_email = row[9];
survey.date_created = ConvertUnixTimeStampToDateTime_(row[10]);
survey.date_updated = ConvertUnixTimeStampToDateTime_(row[11]);
survey.fiscal_year = row[12];
survey.documents = GetDocumentsById_DataLayer_({
program_id: row[13]
});
surveys.push(survey);
}
}
surveys.success = true;
return surveys;
}
function GetDataRows_(Sheet_Id, SheetName) {
var sheet = GetSheet_(Sheet_Id, SheetName);
var rows = [];
if (sheet) {
rows = sheet.getDataRange().getValues();
}
return rows;
}
function GetSheet_(Sheet_Id, SheetName) {
var ss = SpreadsheetApp.openById(Sheet_Id);
var sheet = ss.getSheetByName(SheetName);
return sheet;
}
function GetReportingPeriodNameById_(id, reporting_periods) {
if (id) {
for (var i = 0; i < reporting_periods.length; i++) {
if (reporting_periods[i].id == id) {
return reporting_periods[i].value
}
}
return "Reporting Period Not Found"
} else {
return "Reporting Period Not Found"
}
}
function GetDocumentsById_DataLayer_(data) {
var rows = GetDataRows_(DATA_SPREAD_SHEET_ID, PROGAM_DOCUMENTS_PAGE);
var documents = [];
var program_id = data.program_id.trim();
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_program_id = row[1];
var is_active = row[6];
if(is_active === true){
if (found_program_id === program_id) {
var document = {};
document.document_id = row[0];
document.program_id = row[1];
document.document_name = row[2];
document.file_id = row[3];
document.file_name = row[4];
document.file_url = row[5]
document.date_created = ConvertUnixTimeStampToDateTime_(row[7]);
document.date_updated = ConvertUnixTimeStampToDateTime_(row[8]);
documents.push(document);
}
}
}
documents.success = true;
return documents;
}
function ConvertUnixTimeStampToDateTime_(unix_timestamp) {
if (!unix_timestamp) {
return "";
}
var a = new Date(unix_timestamp * 1000);
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
var time = a.getMonth() + "/" + date + "/" + year + " " + hour + ":" + min + ":" + sec;
return time;
}
This code mostly works fine, except when it is in a loop that gets called 100 times or so, then things lag and can take a minute or more to process. The sheets aren't that big, less that 200 rows and 15 columns.
thanks

The reason for performance depreciation is the GetDataRows_ function, because it makes repeated calls to Spreadsheet.openById(), ss.getSheetByName(SheetName);. You could try using a global map to cache these objects. For example, Use a Spreadsheet map
const globalSSMap = new Map();//global SS map
Then your getter functions can be rewritten. For eg, to get ss, use
if(!globalSSMap.has(Sheet_id)) globalSSMap.set(Sheet_id,SpreadsheetApp.openById(Sheet_Id));
var ss = globalSSMap.get(Sheet_id);

You can refer to this sample code:
Data_Layer.gs
function GetAllDataByManager_DataLayer_(loggedin_user) {
var ss = SpreadsheetApp.openById(DATA_SPREAD_SHEET_ID);
var sheets = ss.getSheets();
// create sheet objects
var sheetData = {};
sheets.forEach(sheet => {
sheetData[sheet.getName()] = sheet.getDataRange().getValues();
})
var program_rows = sheetData[PROGRAM_MANAGERS];
var ip_ids = [];
var Company_data = [];
var runtimeCountStart = new Date();
//first search to make sure logged in user exists, and is marked as Active == True and is marked as an Admin
//if they exist, add their ID to the list
//Should only see records for the logged in user if
//they are either listed as the primary manager (company tab)
//or they are listed as an additional manager (program managers tab)
for (var i = 1; i < program_rows.length; i++) {
var row = program_rows[i];
var found_admin_email = row[2];
var found_is_active = row[10];
if (found_admin_email == loggedin_user && found_is_active == true) {
ip_ids.push(row[1])
}
}
var partner_rows = sheetData[PARTNER_PAGE];
for (var i = 1; i < partner_rows.length; i++) {
var partner_row = partner_rows[i]
var found_partner_id = partner_row[0];
var add_record = false;
if(ip_ids.includes(found_partner_id)){
add_record = true;
}else{
var found_cor_email = partner_row[5]
if(loggedin_user.toUpperCase() == found_cor_email.toUpperCase()){
add_record = true;
}
}
if(add_record == true){
var partner = {
ip_id: partner_row[0],
ip_name: partner_row[1],
ip_poc_name: partner_row[2],
ip_poc_email: partner_row[3],
manager_name: partner_row[4],
manager_email: partner_row[5],
is_active: partner_row[6],
date_created: partner_row[7],
created_by: partner_row[8],
partner_programs: GetAllProgramDataByIP_DataLayer_(sheetData, found_partner_id),
partner_notes: GetProgramNarrativesByPartnerID_DataLayer_(sheetData, found_partner_id),
partner_reports: GetAllReportByPartnerID_DataLayer_(sheetData, found_partner_id)
};
Company_data.push(partner)
}
}
stop = new Date();
newRuntime = Number(stop) - Number(runtimeCountStart);
newRuntime = (newRuntime /1000)/60
return Company_data;
}
function GetAllProgramDataByIP_DataLayer_(sheetData, ip_id) {
var rows = sheetData[PROGRAM_PAGE];
var programs = [];
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_partner_id = row[1];
var program = {}
if (found_partner_id === ip_id) {
program.program_id = row[0].toString();
program.partner_id = row[1].toString();
program.program_name = row[2].toString();
program.program_country = row[3].toString();
program.program_background = row[4].toString();
program.program_objectives = row[5].toString();
program.program_justification = row[6].toString();
program.program_start_date = row[7].toString();
program.program_status = row[8].toString();
program.program_contract_number = row[9].toString();
program.is_active = row[10]
program.date_created = ConvertUnixTimeStampToDateTime_(row[11].toString());
program.date_updated = ConvertUnixTimeStampToDateTime_(row[12].toString());
program.success = true;
programs.push(program)
}
}
return programs;
}
function GetProgramNarrativesByPartnerID_DataLayer_(sheetData, partner_id) {
var rows = sheetData[PROGRAM_NARRATIVE_NOTE];
var programs_notes = [];
var response = {};
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_partner_id = row[2];
var is_active = row[7];
if(is_active === true){
if (found_partner_id === partner_id) {
var note = {};
note.note_id = row[0];
note.program_id = row[1];
note.company_guid = row[2];
note.note_title = htmlEscape_(row[3]);
note.note_desc = htmlEscape_(row[4]);
note.note_reportingPeriod = row[5];
note.activity_theme = row[6];
note.date_created = ConvertUnixTimeStampToDateTime_(row[8]);
note.date_updated = ConvertUnixTimeStampToDateTime_(row[9]);
programs_notes.push(note);
}
}
}
response.success = true;
response.programs_notes = programs_notes
return response;
}
function GetAllReportByPartnerID_DataLayer_(sheetData, partner_id) {
//get all reporting period for program
var rows = sheetData[RESPONSE_PAGE];
var surveys = [];
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_partner_id = row[2];
if (found_partner_id == partner_id) {
var survey = {};
survey.indicator_id = row[0];
survey.program_id = row[1];
survey.company_guid = row[2];
survey.survey_response = row[3];
survey.reporting_period = row[5];
survey.is_final_report = row[6];
survey.is_submitted = row[7];
survey.submitted_by = row[8];
survey.submitted_by_email = row[9];
survey.date_created = ConvertUnixTimeStampToDateTime_(row[10]);
survey.date_updated = ConvertUnixTimeStampToDateTime_(row[11]);
survey.fiscal_year = row[12];
surveys.push(survey);
}
}
surveys.success = true;
return surveys;
}
Helper_Functions.gs
function ConvertUnixTimeStampToDateTime_(unix_timestamp) {
if (!unix_timestamp) {
return "";
}
var a = new Date(unix_timestamp * 1000);
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
var time = a.getMonth() + "/" + date + "/" + year + " " + hour + ":" + min + ":" + sec;
return time;
}
function CreateGUID_() {
return Utilities.getUuid();
}
function htmlEscape_(str) {
str = str.toString();
if (str && str.length > 0) {
return str.replace(/<[^>]+>/g, "")
} else {
return "";
}
}
Note:
I didn't see GetDocumentsById_DataLayer_ and survey.documents in the shared script.
I just looked for something to improve in your main function GetAllDataByManager_DataLayer_() where nested loop occur when you are checking your partner_rows variable.
I don't think there's any more we can do regarding your nested loop check.
Modifications Done:
Although you prevented repeating the calls for Spreadsheet.openById(), you still make individual calls when you map your sheet objects since you use ss.getSheetByName(SheetName); to get individual sheet object based on the SheetName and even reading the sheet values during every loop for 3 different sheets
What I did is to get all your sheet object available in your spreadsheet using getSheets(), get its data range values then map them based on their sheet name. As what was suggested by #TheMaster in the other answer
Remove unnecessary functions in Helper_Functions.gs
Execution Log:
For the code changes, refer to the last 2 recent Web Apps execution logs. Compare it to the first execution

Related

Faster way to collect data from JSON than looping in spreadsheet

I am learning Javascript and this is my first time working with Google Sheets Apps Script. What I am doing is taking a large JSON file and importing it into my sheet. After that I am populating a few hundred properties based on the key:value found in the JSON.
This is how it kinda works right now:
Go to first column and first row of my sheet.
Get the name (property name).
Search the JSON for the key and then grab the value.
Update a neighbor cell with the value found in the JSON.
Right now it all works the only issue is it seems to be pretty slow. It takes about .5-1 second per lookup and when I have 200+ properties it just seems slow. This might just be a limitation or it might be my logic.
My sheet can be found here: https://docs.google.com/spreadsheets/d/1tt3eh1RjL_CbUIaPzj10DbocgyDC0iNRIba2B4YTGgg/edit#gid=0
My function that does everything:
function parse() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(2,1);
var range1 = sheet.getRange("A2");
var cell = range.getCell(1, 1);
var event_line = cell.getValue();
var tmp = event_line.split(". ");
var col_number = tmp[0];
var event_name = tmp[1];
event_json = get_json_from_cell(col_number);
const obj = JSON.parse(event_json);
var traits = obj.context.traits;
var properties = obj.properties;
//Get the range for the section where properties are
var traits_range = sheet.getRange("contextTraits");
var allprop = sheet.getRange("testAll");
var alllen = allprop.getNumRows();
var length = traits_range.getNumRows();
for (var i = 1; i < length; i++) {
var cell = traits_range.getCell(i, 1);
var req = traits_range.getCell(i, 4).getValue();
var trait = cell.getValue();
var result = traits[trait];
var result_cell = traits_range.getCell(i, 3);
if (result == undefined) {
if (req == "y"){
result = "MISSING REQ";
result_cell.setBackground("red");
} else {
result = "MISSING";
result_cell.setBackground("green");
}
} else {
result_cell.setBackground("blue");
}
result_cell.setValue(result);
Logger.log(result);
}
for (var i = 1; i < alllen; i++) {
var cell = allprop.getCell(i,1);
var req = allprop.getCell(i, 4).getValue();
var prop = cell.getValue();
var result = properties[prop];
var result_cell = allprop.getCell(i, 3);
if (result == undefined) {
if (req == "y"){
result = "MISSING REQ";
result_cell.setBackground("red");
} else {
result = "MISSING";
result_cell.setBackground("green");
}
} else {
result_cell.setBackground("blue");
}
result_cell.setValue(result);
}
Logger.log(result);
}

For loop not iterating a variable

I'm just learning javascript and I'm trying to update woocommerce products through GAS.
The issue in question is the following:
I have a variable that parses the response from woocommerce
for (let sku of skuSearch) {
var surl = website + "/wp-json/wc/v3/products?consumer_key=" + ck + "&consumer_secret=" + cs + "&sku=" + sku;
var url = surl
Logger.log(url)
var result = UrlFetchApp.fetch(url, optionsGet);
if (result.getResponseCode() == 200) {
var wooProducts = JSON.parse(result.getContentText());
Logger.log(result.getContentText());
}
Then I have another for to iterate and from a new array that contains id + sku of wooProducts and price from a different variable that takes the updated price from my sheet:
var idLength = wooProducts.length;
Logger.log(idLength);
for (var i = 0; i < idLength; i++) {
var container = [];
Logger.log(i);
container.push({
id: wooProducts[i]["id"],
sku: wooProducts[i]["sku"],
price: data[i]["price"],
});
I can't tell exactly why it doesn't work. I mean the for loop works, it pushes id, sku and price in every loop, it's just that data[i] only provides the first ¿object? instead of looping like wooProducts which add +1 at every loop.
I'll copy 3 loops so it's crystal clear, I'm not sure it's already clear.
Loop 1:
[{"id":1622,"sku":"PD-1000-B","price":8145.9}]
Loop 2:
[{"id":1624,"sku":"PD-1007-A","price":8145.9}]
Loop 3:
[{"id":1625,"sku":"PD-1014","price":8145.9}]
As you can see id+sku change but price doesn't.
For further context, I'll include the data variable that is declaed outside the For:
const data = codigos.map(function(codigos, indice) {
return {
sku: codigos[0],
price: precios[indice][0]
}
})
//** EDIT:
I'm adding the entire code so it makes more sense maybe?
function getDataloopwoo() {
var ck = 'xxx'
var cs = 'xxx'
var website = 'xxx'
var optionsGet =
{
"method": "GET",
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
"muteHttpExceptions": true,
};
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('PreciosBULK');
var codigos = sheet.getRange("A2:A").getValues();
var precios = sheet.getRange("B2:B").getValues();
var skuSearch = sheet.getRange("A2:A").getValues();
const data = codigos.map(function(codigos, indice) {
return {
sku: codigos[0],
price: precios[indice][0]
}
})
Logger.log(skuSearch)
for (let sku of skuSearch) {
var surl = website + "/wp-json/wc/v3/products?consumer_key=" + ck + "&consumer_secret=" + cs + "&sku=" + sku;
var url = surl
Logger.log(url)
var result = UrlFetchApp.fetch(url, optionsGet);
if (result.getResponseCode() == 200) {
var wooProducts = JSON.parse(result.getContentText());
Logger.log(result.getContentText());
}
var idLength = wooProducts.length;
Logger.log(idLength);
var container = [];
for (var i = 0; i < idLength; i++) {
Logger.log(i);
container.push({
id: wooProducts[i]["id"],
sku: wooProducts[i]["sku"],
price: data[i]["price"],
});
Logger.log(container);
var wooBatch = JSON.stringify(container);
Logger.log(wooBatch);
}
}
}
// FINAL EDIT with "solve":
So I figured it was inefficient to ask by 1 sku at a time, so now I'm asking by the 100, and paginating with a while if and saving id, sku, price to the container array.
I will need now to compare the container array to the array with the updated prices and form a new array with id, sku and updated price, I'm reading up on that right now. The code:
function getDataloopwoo() {
var ck = 'xx'
var cs = 'xx'
var website = 'xx'
var optionsGet =
{
"method": "GET",
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
"muteHttpExceptions": true,
};
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('PreciosBULK');
var codigos = sheet.getRange("A2:A").getValues();
var precios = sheet.getRange("B2:B").getValues();
const data = codigos.map(function(codigos, indice) {
return {
sku: codigos[0],
price: precios[indice][0]
}
})
var container = [];
var surl = website + "/wp-json/wc/v3/products?consumer_key=" + ck + "&consumer_secret=" + cs + "&per_page=100";
var url = surl
//Logger.log(url)
var result = UrlFetchApp.fetch(url, optionsGet);
var headers = result.getAllHeaders();
var total_pages = headers['x-wp-totalpages'];
var pages_count = 0;
while (pages_count < total_pages) {
if (result.getResponseCode() == 200) {
var wooProducts = JSON.parse(result.getContentText());
//Logger.log(result.getContentText());
}
for (var i = 0; i < wooProducts.length; i++) {
//Logger.log(i);
container.push({
id: wooProducts[i]["id"],
sku: wooProducts[i]["sku"],
price: wooProducts[i]["price"],
});
Logger.log(container);
}
pages_count++;
if (pages_count < total_pages){
var surl = website + "/wp-json/wc/v3/products?consumer_key=" + ck + "&consumer_secret=" + cs + "&per_page=100" + "&page=" + (pages_count + 1);
var url = surl
var result = UrlFetchApp.fetch(url, optionsGet);
Logger.log(url);
}
}
}
You're reseting the array container in every iteration of the loop:
for (var i = 0; i < idLength; i++) {
var container = []; // <-----------------here
...
container.push({
...
I think the array should be defined outside the loop:
var container = [];
for (var i = 0; i < idLength; i++) {
...
container.push({
...

How do I put multiple things in an array in the local storage and pick out the one i need?

I am making this announcement program for teachers and students where the teacher puts in values such as grade gender club and the announcement, and a student page that lets you choose the grade gender and club you are in to show the announcements that are there for those values. Now I have a problem. I have created an array which allows for me to put in multiple different announcements but I cant get the array to function and show up in the student page. Here are the 2 different js codes
Teacher page js code
var teacherGrade = [];
var teacherGender = [];
var teacherClub = [];
var teacherAnnouncement = [];
var counter = 0;
function getData() {
//alert("here");
teacherGrade[counter] = document.getElementById("htmlTGrade").value
teacherGender[counter] = document.getElementById("htmlTGender").value
teacherClub[counter] = document.getElementById("htmlTClub").value
teacherAnnouncement[counter] = document.getElementById("htmlTAnnouncement").value
localStorage.setItem("teacherGradeKey", JSON.stringify(teacherGrade));
localStorage.setItem("teacherGenderKey", JSON.stringify(teacherGender));
localStorage.setItem("teacherClubKey", JSON.stringify(teacherClub));
localStorage.setItem("teacherAnnouncementKey", JSON.stringify(teacherAnnouncement));
counter++;
}
function getExsistingAnnouncement() {
if (JSON.parse(localStorage.getItem("teacherGradeKey")) != null) {
teacheGrade = JSON.parse(localStorage.getItem("teacherGradeKey"));
teacherGender = JSON.parse(localStorage.getItem("teacherGenderKey"));
teacherClub = JSON.parse(localStorage.getItem("teacherClubKey"));
teacherAnnouncement = JSON.parse(localStorage.getItem("teacherAnnouncementKey"));
counter = teacherGrade.length;
}
}
//function checkArray() {
//var checkGrade = JSON.parse(localStorage.getItem("teacherGrade"));
//alert("Grade from Local Storage = ", checkGrade);
//var checkGender = JSON.parse(localStorage.getItem("teacherGender"));
//alert("Gender from Local Storage = ", checkGender);
//var checkClub = JSON.parse(localStorage.getItem("teacherClub"));
//alert("Club from Local Storage = ", checkClub);
//var checkAnnouncement = JSON.parse(localStorage.getItem("teacherAnnouncement"));
//alert("Announcement from Local Storage = ", checkAnnouncement);
//}
Student Page js code
var teacherGrade = [];
var teacherGender = [];
var teacherClub = [];
var teacherAnnouncement = [];
var studentGrade;
var studentGender;
var studentClub;
var counter = 0;
var annoucnementTextHolder = " ";
function displayAnnouncement() {
teacherGrade[counter] = localStorage.getItem("teacherGradeKey");
teacherGender[counter] = localStorage.getItem("teacherGenderKey");
teacherClub[counter] = localStorage.getItem("teacherClubKey");
teacherAnnouncement[counter] = localStorage.getItem("teacherAnnouncementKey");
studentGrade = localStorage.getItem("studentGradeKey");
studentGender = localStorage.getItem("studentGenderKey");
studentClub = localStorage.getItem("studentClubKey");
annoucnementTextHolder += teacherAnnouncement;
counter++;
for (var i = 0; i < teacherGrade.length; i++) {
if ((teacherGrade[i] == studentGrade || teacherGrade[i] == "Select all") && (teacherGender[i] == studentGender || teacherGender[i] == "Select all") && (teacherClub[i] == studentClub || teacherClub[i] == "Select all")) {} else {
document.getElementById("htmlSViewerText").innerHTML = "Sorry no announcement"
}
}
document.getElementById("htmlSViewerText").innerHTML = annoucnementTextHolder;
}

Delete Duplicate Data using Google Script

I am trying to make a script to automate deleting duplicate data based on column A. This is the current script I am using and it works.
// This scripts works but deleting new data instead of old data
function removeDuplicates() {
var sheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName(sheetName);
var vA = sh.getDataRange().getValues();
var hA = vA[0];
var hObj = {};
hA.forEach(function(e, i) {
hObj[e] = i;
});
var uA = [];
var d = 0;
for (var i = 0; i <= vA.length; i++) {
if (uA.indexOf(vA[i][hObj['key']]) == -1) {
uA.push(vA[i][hObj['key']]);
} else {
//sh.deleteRow(i + 1 - d++);
sh.deleteRow((parseInt(i)+1) - d);
d++;
}
}
};
But this one is deleting the newly added row, what I want to achieve is it should delete the old duplicate row instead. How can I do that?
In else part instead of using i which represent your current row, use the indexOf the row you want to delete. Delete it first and then push the new one into array
// This scripts works but deleting new data instead of old data
function removeDuplicates() {
var sheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName(sheetName);
var vA = sh.getDataRange().getValues();
var hA = vA[0];
var hObj = {};
hA.forEach(function(e, i) {
hObj[e] = i;
});
var uA = [];
var d = 0;
for (var i = 0; i <= vA.length; i++) {
if (uA.indexOf(vA[i][hObj['key']]) == -1) {
uA.push(vA[i][hObj['key']]);
} else {
//sh.deleteRow(i + 1 - d++);
let j = uA.indexOf(vA[i][hObj['key']]);
sh.deleteRow((parseInt(j)+1) - d);
d++;
uA.push(vA[i][hObj['key']]);
}
}
};

Google sheets incorrect range width when no cmc matches

I am using this function to pull information from coinmarketcap using their v2 api. The problem I am getting is that if a "website_slug" does not exist on coinmarketcap, I get an incorrect range width error instead of the function just putting xxx in the cell. This can be recreated by having a cell in column B that doesn't match a website_slug on cmc (https://api.coinmarketcap.com/v2/ticker/).
function getMarketCap(sheetname) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetname);
var assets = [];
var idRange = sheet.getRange("B1:B");
var lastRow = getLastRowOfRange(idRange);
var cellRange = sheet.getRange(1, 2, lastRow).getValues();
var mcRange = sheet.getRange(1, 3, lastRow);
var mcValues = [];
for (var i = 0; i < cellRange.length; i++) {
assets[i] = cellRange[i];
}
var req = [];
for (var i = 0; i < 16; i++) {
req.push({
muteHttpExceptions: true,
method: "get",
url: "https://api.coinmarketcap.com/v2/ticker/?start=" + (i * 100 + 1),
});
}
var responses = UrlFetchApp.fetchAll(req);
var res = responses.filter(function(e){return e.getResponseCode() == 200}).map(function(e){return JSON.parse(e.getContentText())});
if (responses.length != res.length) Logger.log("%s errors occurred.", responses.length - res.length);
var mcValues = [];
assets.forEach(function(e, h) {
mcValues[h] = []
res.some(function(f) {
Object.keys(f.data).some(function(g) {
if (f.data[g].website_slug == e[0]) {
mcValues[h][0] = f.data[g].quotes.USD.market_cap;
return true;
}
});
if (mcValues[h][0]) return true;
});
if (!mcValues[h][0]) mcValues[h][0] = 'xxx';
});
mcRange.setValues(mcValues);
}

Categories

Resources