Code runs too slow - javascript

I'm trying to run a code that copies values from one spreadsheet and copies them to another, however the order is not the same(hard to make it an array). In some cases it also prints 'Unknown' and in some it also formats some cells. However it makes way to much time to finish. Is there a way to improve it?
function move() {
var sss = SpreadsheetApp.openById('xx');
var sourceSheet = sss.getSheetByName('CJ_Products');
var destinationSheet = sss.getSheetByName('Product2');
var lastRow = sourceSheet.getRange(sourceSheet.getLastRow(), 1,1,1).getRow()
var i = 1
while(i<=lastRow){
var rowInt = destinationSheet.getRange(destinationSheet.getLastRow()+1, 4,1,1).getRow() //get row number
destinationSheet.getRange('A' + rowInt).setFormula('=Month(D'+rowInt+')')
destinationSheet.getRange('B' + rowInt).setFormula('=Weekday(D'+rowInt+')')
destinationSheet.getRange('C' + rowInt).setFormula('=Day(D'+rowInt+')')
destinationSheet.getRange('D' + rowInt).setValue(sourceSheet.getRange('A'+i).getValues()) //move from the source to destination
destinationSheet.getRange('E' + rowInt+':F'+rowInt).setValue('Unknown') //set to Unknown
destinationSheet.getRange('H' + rowInt+':J'+rowInt).setValue('Unknown')
destinationSheet.getRange('J' + rowInt).setValue('CJ')
destinationSheet.getRange('K' + rowInt).setValue(sourceSheet.getRange('B' +i).getValues())
destinationSheet.getRange('L' + rowInt).setValue(sourceSheet.getRange('E' +i).getValues())
destinationSheet.getRange('M' + rowInt).setValue(sourceSheet.getRange('F' +i).getValues())
destinationSheet.getRange('N' + rowInt).setValue(sourceSheet.getRange('J' +i).getValues())
destinationSheet.getRange('S' + rowInt).setValue(sourceSheet.getRange('G' +i).getValues())
destinationSheet.getRange('T' + rowInt).setValue(sourceSheet.getRange('H' +i).getValues())
destinationSheet.getRange('O' + rowInt).setFormula('=S'+rowInt+'*GOOGLEFINANCE("currency:EURUSD")')
destinationSheet.getRange('P' + rowInt).setFormula('=T'+rowInt+'*GOOGLEFINANCE("currency:EURUSD")')
destinationSheet.getRange('Q' + rowInt).setFormula('=P'+rowInt+'/T'+rowInt)
destinationSheet.getRange('O' + rowInt+':Q'+rowInt).setNumberFormat('0.00$')
i = i+1
}
}

The code should be optimised:
You do all calculations in a loop
You use getValue and setValue instead of faster functions getValues, setValues
Instead of this concentrate your loop to do a single call:
var rowInt = destinationSheet.getRange(destinationSheet.getLastRow()+1, 4,1,1).getRow()
try to figure out how to find the first row outside the loop and then increment this value:
var rowStart = destinationSheet.getRange(destinationSheet.getLastRow()+1, 4,1,1).getRow();
for (var row = rowStart; row <= lastRow, row++)
{
// some code...
}
Use arrays and then copy the value from arrays into ranges:
var formulas = [];
for (var row = rowStart; row <= lastRow, row++)
{
// some code...
formulas.push(['=Month(D'+ row + ')']);
}
var rangeToPateFormulas = destinationSheet.getRange('A' + rowStart + ':A' + lastRow);
rangeToPateFormulas.setFormulas(formulas);
And so on. See more info:
https://developers.google.com/apps-script/reference/spreadsheet/range
https://developers.google.com/apps-script/guides/support/best-practices

Related

Google sheets script - Strip extra data from a second line and add it to the first line

I'm trying to build a script in google sheets script that will iterate down a sheet, row by row, and if it encounters an ID number in the first cell of that row that is identical to the one above it, it strips out the data from every cell EXCEPT Column A and B, and appends it to the line above. Ideally, this would work with an indeterminate number of duplicate row IDs, might be 2, might be 3, might be 4.
After stripping out the data I want to keep (eg colums C and onward), I then want to delete the entire contents of the processed duplicate ID row, but I just haven't put that in my script until after it copies the data correctly.
In this example, sheet rows 6, 7 and 8 have identical ID numbers (Column A)
Here is the result I'm trying to get:
And here is the result I'm getting:
I've tried a number of different ways, and torn down and rebuilt my script a couple of times without getting the result I want:
function stripMiner() {
var ss = SpreadsheetApp.openById("1WDPoTICQvdruxfhAwHLtA51fz05DqyZ-NhNfpAyPO6Y");
var mainSheet = ss.getSheetByName("Main");
var startRow = 5;
var numRows = mainSheet.getLastRow();//obtains the last row in the sheet
var setrgh = mainSheet
var dataRange = mainSheet.getRange(startRow, 1,4,120); //rowStart, columnStart, row count, column count, the columncount needs to be large enough to encompass all your ancillary data
var data = dataRange.getValues();
var iter = 0;
var maxItRow = 4;
var prevIdNum = 0;
var dupCount = 1;
var cc1 = "P5"; //Cells to dump check values into
var cc2 = "P6";
var dumpRow = startRow;
//if (numRows >= maxItRow){var maxIter = maxItRow;}
for (i in data){
if (iter != maxItRow){ //making sure we haven't gone over the iteration limit
var row = data[i];
var idNum = (row[0]);
var jCount = 0; //resets icount if the id number is different icount is used to skip some cells in a row
if (idNum == prevIdNum){//only proceed if we've hit another line with the same ID number
dupCount = +1; //increment the dupcount value
mainSheet.getRange(cc2).setValue("dupCount"+dupCount); //dupcount check value
var rowIterStart = 5; //RowIterStart is used to add to rowiter, EG if your data is 20 columns wide, and you start transposing from column 4, then this will want to be about 17
var rowIter = 1;
for (j in row){
if (jCount >= 2){ //the integer here is the column where it will begin to transpose data
mainSheet.getRange(dumpRow-1,(rowIterStart*dupCount)+(rowIter)).setValue(row[j]); //startRow+(iter-dupCount)
mainSheet.getRange(cc1).setValue("dumprow"+dumpRow);
}
rowIter+=1;
jCount +=1;
}
}
else{
var dupCount = 1;
dumpRow +=1;
}
prevIdNum = (row[0]); //sets the most recently processed rows ID number
}
iter +=1;
}
}
I'm not quite sure where I'm going wrong. Does anyone have any suggestions? Thanks!
(Also I'm still just a beginner with this so if I've overlooked anything obvious or taken the wrong approach to do this, I apologize!)
The results for the questioner's code in the case of copied data arise from a convoluted loop. In essence, though duplicates were identified, there was a mis-counting to assign the copied data to the correct rowID. So far as clearing data, no provision was included.
The following code works to meet the questioner's goals, though it is far from perfect.
At present, the recalculation of the "last column" after copy each duplicate is an absolute rather than than a row-based figure. So, if a duplicate was detected for, say, ID=3, the data would be copied to column 12 rather than column 6. This requires the addition of a simple dupID row counter.
The second factor is the calculation of the last column in the spreadsheet.
var dataRange = mainSheet.getRange(startRow, 1,Rowlast+1,120);
The questioner used 120 columns; and I have retained that number simply for the sake of consistency. The questioner should re-assess whether this is excessive.
function ejb_so_5284922701() {
var ss = SpreadsheetApp.openById("<< insert questioners spreadsheet ID>>");
var mainSheet = ss.getSheetByName("<< insert questioner's sheet name >>");
var startRow = 5;
// calculate the last row containing data
var Rowvals = ss.getRange("A5:A").getValues();
var Rowlast = Rowvals.filter(String).length; //6
Logger.log("last row = " + Rowlast); // DEBUG
// calculate the last column containing data
var cell = mainSheet.getRange("A5"); //or however you determine "cell"
var drCol = mainSheet.getDataRange().getLastColumn();
Logger.log('getLastColumn = ' + drCol); //DEBUG
for (var i = drCol; i >= 1; i--) {
if (mainSheet.getRange(cell.getRow(), i).getValue() != "") {
break;
}
}
var lastColumn = i;
Logger.log("Last column with data = " + lastColumn); //DEBUG
var setrgh = mainSheet
// numColumns neds to be reviewed
var dataRange = mainSheet.getRange(startRow, 1, Rowlast + 1, 120); //rowStart, columnStart, row count, column count, the column count needs to be large enough to encompass all your ancillary data
// start row = 5, 1= column A, 4, rows, 120, columns
Logger.log("startRow = " + startRow + ", and the datarange = " + dataRange.getA1Notation()); //DEBUG
var data = dataRange.getValues();
Logger.log("length of data =" + data.length); //DEBUG
var lastid = 0;
for (i = 0; i < data.length; i++) {
if (i == 0) {
// if this is the first row, then assign anything but zero to last id
lastid = 100;
Logger.log(" this is the first row; set last id to 100");
}
var thisid = data[i][0];
// evaluate whether this is a duplicate ID
if (thisid == lastid) {
// this is a dup
Logger.log("i=" + i + ". This is a dup" + ", name is " + data[i][2]); //DEBUG
var stufftocopyrange = mainSheet.getRange(startRow + i, 3, 1, 3);
var stufftocopy = stufftocopyrange.getValues();
Logger.log("the range to copy is " + stufftocopyrange.getA1Notation()); //DEBUG
var targetrange = mainSheet.getRange(startRow + lastid - 1, lastColumn + 1, 1, 3);
targetrange.setValues(stufftocopy);
lastColumn = lastColumn + 3;
var duprange = mainSheet.getRange(startRow + i, 1, 1, 5);
Logger.log("the range to clear is " + duprange.getA1Notation()); //DEBUG
duprange.clearContent();
} else {
// no dup
//assign lastid value
var lastid = thisid;
Logger.log("i=" + i + ". No dup. Last id set to " + lastid); // DEBUG
} // if
} // end for loop
}
BEFORE
AFTER
The solutions previously posted didn't quite get the result I needed, however I managed to cobble together something that works for my purposes. It expects to see data in the format like:
And turn it into something like this:
Where it uses duplicate ID numbers (with an indeterminite number of duplicates) to pull only certain columns of data from the duplicate lines and append it to the first line.
function stripMiner() {
var ss = SpreadsheetApp.openById("1WDPoTICQvdruxfhAwHLtA51fz05DqyZ-NhNfpAyPO6Y");
var mainSheet = ss.getSheetByName("Main");
var startRow = 5;
var numRows = mainSheet.getLastRow();//obtains the last row in the sheet
var setrgh = mainSheet
var dataRange = mainSheet.getRange(startRow, 1,3,120); //rowStart, columnStart, row count, column count, the columncount needs to be large enough to encompass all your ancillary data
var data = dataRange.getValues();
var iter = 0;
var maxItRow = 4;
var prevIdNum = 0;
var dupCount = 1;
var cc1 = "P5"; //Cells to dump check values into
var cc2 = "P6";
var dumpRow = startRow;
//if (numRows >= maxItRow){var maxIter = maxItRow;}
for (i in data){
if (iter != maxItRow){ //making sure we haven't gone over the iteration limit
var row = data[i];
var idNum = (row[0]);
var jCount = 0; //resets icount if the id number is different icount is used to skip some cells in a row
if (idNum == prevIdNum){//only proceed if we've hit another line with the same ID number
dupCount = +1; //increment the dupcount value
mainSheet.getRange(cc2).setValue("dupCount"+dupCount); //dupcount check value
var rowIterStart = 5; //RowIterStart is used to add to rowiter, EG if your data is 20 columns wide, and you start transposing from column 4, then this will want to be about 17
var rowIter = 1;
for (j in row){
if (jCount >= 2){ //the integer here is the column where it will begin to transpose data
mainSheet.getRange(dumpRow-2,(rowIterStart*dupCount)+(rowIter)).setValue(row[j]); //startRow+(iter-dupCount)
mainSheet.getRange(cc1).setValue("dumprow"+dumpRow);
}
rowIter+=1;
jCount +=1;
}
}
else{
var dupCount = 1;
dumpRow +=1;
}
prevIdNum = (row[0]); //sets the most recently processed rows ID number
}
iter +=1;
}
}
Hopefully someone else who wants to do a similar thing can make use of this too.

Concatenation of single quote marks Google Script

I have three columns of data
selector label option list
time you personally have been engaged with uscan label_1 Arts
time you personally have been engaged with uscan label_2 Children’s Issues
time you personally have been engaged with uscan label_3 Coaching
time you personally have been engaged with uscan label_4 Community Development
time you personally have been engaged with uscan label_5 Conflict
time you personally have been engaged with uscan label_6 Consulting
I am trying to concatenate these columns so that in the 4th column I get
option {
label: "Label_1;
selector: ["time you personally have been engaged with uscan"="Arts"];
}
option {
label: "Label_2;
selector: ["time you personally have been engaged with uscan"="Children’s Issues"];
}
etc
My attempt
result[i] = [""option {label:""" + values[i][0] + "";" + "selector: [" + values[i][0] + ""=" + + values[i][1] + ""];}"];
Foiled by all the single quotes that are required
Thank you
GS
function OptionsList() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("OptionList");
var lr = sheet.getLastRow();
var values = sheet.getRange(2, 1, lr,3).getValues();
var result = [];
//Add items to results
for(var i=0; i<lr; i++){
result[i] = [""option {label:""" + values[i][0] + "";" + "selector: [" + values[i][0] + ""=" + + values[i][1] + ""];}"];
}
//Post back to column 4 starting on row 2
sheet.getRange(2, 4, lr, 1).setValues(result);
}
How about this modification?
Modification points :
About result[i]
" was escaped like \".
Line break was added like \n.
Remove the empty cells by filter().
Modified script :
function OptionsList() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("OptionList");
var lr = sheet.getLastRow();
var values = sheet.getRange(2, 1, lr, 3).getValues();
values = values.filter(function(e){return e[0] && e[1] && e[2]}); // Added
var result = [];
//Add items to results
for(var i=0; i<values.length; i++){ // Modified
result[i] = ["option {\nlabel: \"" + values[i][1] + ";\n" + "selector: [\"" + values[i][0] + "\"=\"" + values[i][2] + "\"];\n}"]; // Modified
}
//Post back to column 4 starting on row 2
sheet.getRange(2, 4, result.length, 1).setValues(result); // Modified
}
Note :
For example, is it required to be " after "Label_1 of label: "Label_1;? If you want, please modify as follows.
+ values[i][1] + "\";\n"
Reference :
filter()
If I misunderstand your question, please tell me. I would like to modify it.

Google Sheets Script to Clear/Remove Filters

I have a script in a Google Sheet that clears/removes the filters on all tabs of the Sheet upon opening. It accomplishes this by grabbing the top row, then deleting it and then replacing it without the filters.
The script works, however, it seems like it is too much for Sheets to handle with 6 tabs. When it runs, it leaves 2-3 tabs completely gray without any data displayed. When you double click a gray cell, it returns the following message: "These cells are currently being loaded. Please retry when loading completes". No matter how long I wait, the data doesn't display. If I refresh the page 3 or 4 more times, all tabs will eventually display data.
I'm hoping to either clean up the code or come up with a new script in order to not have to refresh the page. I used the script on a sheet with only two tabs and it worked fine, so I don't think it has to do with the amount of data.
Fair warning: I am an extreme beginner when it comes to this, so I'm sure the code and formatting are pretty ugly.
Here is a link to a copy of the Sheet:
https://docs.google.com/spreadsheets/d/1cg4wVIHPumahQgf5gorc4JQXsG_6l4eg3OhONABx8gs/edit#gid=369791415
And here is the code for the script (it is a repeating chunk of code for each tab):
function myFunction()
{
var row2 = 1 //the row with filter
var rowBefore2 = row2
var Sheet2 = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(Sheet2.getSheets()[1]);
Sheet2.insertRowBefore(row2); //inserts a line before the filter
row2++;
var Line2 = Sheet2.getRange(row2 + ":" + row2); //gets the filter line
Line2.moveTo(Sheet2.getRange(rowBefore2 + ":" + rowBefore2)); //move to
new line
Sheet2.deleteRow(row2); //deletes the filter line - this clears the
filter
var row3 = 1
var rowBefore3 = row3
var Sheet3 = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(Sheet3.getSheets()[2]);
Sheet3.insertRowBefore(row3);
row3++;
var Line3 = Sheet3.getRange(row3 + ":" + row3);
Line3.moveTo(Sheet3.getRange(rowBefore3 + ":" + rowBefore3));
Sheet3.deleteRow(row3);
var row4 = 1 //the row with filter
var rowBefore4 = row4
var Sheet4 = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(Sheet4.getSheets()[3]);
Sheet4.insertRowBefore(row4);
row4++;
var Line4 = Sheet4.getRange(row4 + ":" + row4);
Line4.moveTo(Sheet4.getRange(rowBefore4 + ":" + rowBefore4));
Sheet4.deleteRow(row4);
var row5 = 1 //the row with filter
var rowBefore5 = row5
var Sheet5 = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(Sheet5.getSheets()[4]);
Sheet5.insertRowBefore(row5);
row5++;
var Line5 = Sheet5.getRange(row5 + ":" + row5);
Line5.moveTo(Sheet5.getRange(rowBefore5 + ":" + rowBefore5));
Sheet5.deleteRow(row5);
var row6 = 1
var rowBefore6 = row6
var Sheet6 = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(Sheet6.getSheets()[5]);
Sheet6.insertRowBefore(row6);
row6++;
var Line6 = Sheet6.getRange(row6 + ":" + row6);
Line6.moveTo(Sheet6.getRange(rowBefore6 + ":" + rowBefore6));
Sheet6.deleteRow(row6);
var row7 = 1
var rowBefore7 = row7
var Sheet7 = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(Sheet7.getSheets()[6]);
Sheet7.insertRowBefore(row7);
row7++;
var Line7 = Sheet7.getRange(row7 + ":" + row7);
Line7.moveTo(Sheet7.getRange(rowBefore7 + ":" + rowBefore7));
Sheet7.deleteRow(row7);
}
Loop through your sheets instead of referencing them directly. Then stick your code that you want to do... it should look something like this. I copied your sheet and put the code in there and shared it back to you. It runs through in a few seconds and there are any grey pages. I don't have access to the sheet you are doing an importrange on. So if you find that it is still grey for you with this script, that might be related to the issue.
function removeFilters() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var row1 = 1;
var lastColumn = 20
for (var i = 0; i < sheets.length ; i++ ) {
var sheet = sheets[i];
sheet.activate();
lastColumn = sheet.getLastColumn()
sheet.insertRowBefore(row1); //inserts a line at the top
sheet.getRange(row1+1, 1, 1, lastColumn).moveTo(sheet.getRange("a1"));
Logger.log("value of i: " + i + " and active sheet is: " + sheet.getName());
sheet.deleteRow(row1+1);
}
}
Get an array of all sheets and loop through them:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets =ss.getSheets() //get array of all sheets
for(i=0;i<sheets.length;i++){ //for each sheet
var row2 = 1 //the row with filter
var rowBefore2 = row2
var s=SpreadsheetApp.setActiveSheet(ss.getSheets()[i]);
s.insertRowBefore(row2); //inserts a line before the filter
row2++;
var Line2 = s.getRange(row2 + ":" + row2); //gets the filter line
Line2.moveTo(s.getRange(rowBefore2 + ":" + rowBefore2)); //move to new line
s.deleteRow(row2); //deletes the filter line - this clears the filter
}}

JavaScript Loop Animation Interval

I'm trying to get this loop to return a value, for each value in an array every 1 second.
The returned value is a random value generated earlier, and each loop will add i to the number and output it. (ran[0]+i) (ran[1]+i) etc.
I need the output in the same order as my example, but with a 1 second interval and something to generate my returns/consolelogs instead of having to type in all 4, or however many I use (could be random).
The code is for an animation but I cannot get the SVG working here and its irrelevant to the problem I think.
var ran = [];
var qan = 4;
for(i=0;i<(qan);i++){
rd = Math.floor(Math.random()*360);
ran.push(rd);
};
for(i=0;i<10;i++){
/*need to have (random.length) number of console logs and interval loops by 1 second*/
console.log((ran[0]+i) + " loop " + (i));
console.log((ran[1]+i) + " loop " + (i));
console.log((ran[2]+i) + " loop " + (i));
console.log((ran[3]+i) + " loop " + (i));
};
You may do like this;
var ran = [];
var qan = 4;
for(let i=0;i<(qan);i++){
rd = Math.floor(Math.random()*360);
ran.push(rd);
setTimeout(function(){console.log(ran[i])},1000*i);
}
Or by using var instead of let you can still do like this by utilizing an IIFE to return a callback with an encapsulated i value.
var ran = [];
var qan = 4;
for(var i=0;i<(qan);i++){
rd = Math.floor(Math.random()*360);
ran.push(rd);
setTimeout((function(j){ return function(){ console.log(ran[j]) } })(i),1000*i);
}
Update: I hope i am getting closer.. I just console.log the array itself but the items increase by i in each round. (10 rounds / frames)
var randar = new Array(4).fill().map(e => ~~(Math.random()*360));
console.log("starting random array ",randar); // let's see how the random array starts
for (let i = 0; i < 10; i++){
setTimeout(function(){console.log(randar.map(e=> e+i))} ,1000*i);
}
Note: I use arrows mostly but if you have concerns about IE or Safari then it's best to replace them with conventional function calls.

Return values from rows in a 2d array with a specific value - list results in HTML inside Google Script

I am trying to list three values from each row that contains a specific value in the "Status" column within coded HTML inside a Google Script function. When I run the sendDailyDigest function below, it times out. I am assuming a have some type of error in the for loop inside the html message variable, but I can't seem to figure it out.
I am relatively new to scripting and would be grateful for someone pointing me in the right direction.
Thank you!
function sendDailyDigest() {
var ss = SpreadsheetApp.openById(PRIMARY_SPREADSHEET_ID);
var sheet = ss.getSheets()[0];
var lastRow = sheet.getLastRow();
var data = getRowsData(sheet);
// Count how many requests are awaiting approval
var numSubmitted = 0;
for (var i = 2; i < lastRow; i++) {
if (sheet.getRange(i, getColIndexByName("Status")).getValue() == "SUBMITTED") {
numSubmitted++;
}
}
var message = "<HTML><BODY>"
+ "<P>" + "The following requests await your approval."
+ "<P>" + "\xa0"
+ "<P>" + "<table><tr><td><b>Request ID</b></td><td><b>Requested By</b></td><td><b>Start Date</b></td></tr>"
// List each request pending approval
for (var j = 0; j < data.length; ++j) {
var row = data[j];
row.rowNumber = j + 2;
if (row.status == "SUBMITTED") {
"<tr><td>" + row.rowNumber + "</td><td>" + row.username + "</td><td>" + row.firstDay + "</td></tr>"
}
}
+ "</table>"
+ "</HTML></BODY>";
GmailApp.sendEmail('username#domain.com', numSubmitted + 'Leave Requests Awaiting Approval', '', {htmlBody: message});
}
function getColIndexByName(colName) {
var ss = SpreadsheetApp.openById(PRIMARY_SPREADSHEET_ID);
var sheet = ss.getSheets()[0];
var numColumns = sheet.getLastColumn();
var row = sheet.getRange(1, 1, 1, numColumns).getValues();
for (i in row[0]) {
var name = row[0][i];
if (name == colName) {
return parseInt(i) + 1;
}
}
return -1;
}
/////////////////////////////////////////////////////////////////////////////////
// Code reused from Reading Spreadsheet Data using JavaScript Objects tutorial //
/////////////////////////////////////////////////////////////////////////////////
// getRowsData iterates row by row in the input range and returns an array of objects.
// Each object contains all the data for a given row, indexed by its normalized column name.
// Arguments:
// - sheet: the sheet object that contains the data to be processed
// - range: the exact range of cells where the data is stored
// This argument is optional and it defaults to all the cells except those in the first row
// or all the cells below columnHeadersRowIndex (if defined).
// - columnHeadersRowIndex: specifies the row number where the column names are stored.
// This argument is optional and it defaults to the row immediately above range;
// Returns an Array of objects.
function getRowsData(sheet, range, columnHeadersRowIndex) {
// etc.
The most obvious error I see right now is that you are using the .getLastRow() method, which always times out, even if your code is functional. Instead, try using .getMaxRows(). I used to use the .getLastRow() method at first, but then realized that it doesn't work for some reason. When I used the .getMaxRows() method, the for loop did not time out on me.

Categories

Resources