Google script time out - javascript

My script is timing out, I guess because it's going over the 6 minute limit. Does anyone have an idea how I can optimize it so it runs faster?
The purpose of this script is to copy all the data from one sheet to another sheet, and then fill down some formulas on the destination sheet.
The amount of data copied is quite large (20,000 rows and columns to R) but I don't think it's so much that it should time out? I'm very new to this, so any advice is appreciated!
Here's the script:
function copyPasteTo2ndSheet()
{
var copyURL = 'ThisIsTheOriginSheetURL';
var pasteURL = 'ThisIsTheDestinationSheetURL';
var ssCopy = SpreadsheetApp.openByUrl(copyURL);
var ssPaste = SpreadsheetApp.openByUrl(pasteURL);
var copySheet = ssCopy.getSheetByName('Orders');
var pasteSheet = ssPaste.getSheetByName('Orders');
var lr = copySheet.getLastRow();
var copyData = copySheet.getRange('A2:R'+lr).getDisplayValues();
var pasteLr = pasteSheet.getLastRow();
pasteSheet.getRange('A2:R'+pasteLr).clear();
pasteSheet.getRange('A2:R'+lr).setValues(copyData);
copyPasteFormula(pasteSheet)
}
function copyPasteFormula(sheet)
{
var formulas = sheet.getRange(2, 1, 1, sheet.getLastColumn()).getFormulas()[0];
var lr = sheet.getLastRow();
for(var i in formulas)
{
var formula = formulas[i];
if(formula !== '')
{
var j = parseInt(i)+1;
sheet.getRange(3, j, lr, 1).setFormula(formula);
}
}
}

From the experience that I have had, the sheet.getRange(3, j, lr, 1) line, that has to repeat for 20,000 cells is likely causing the issue.
Commands that get or set to the sheet often take longer and use more memory to run. As a result, it is recommended to either batch your gets or, in this case, you can likely copy an entire row paste it. Copying a formula and pasting it in a different cell will update cell references, just as it does in the UI.

Related

Google Apps Script is taking too much time, is there a way to reduce the runtime?

function dataManp() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("My-Sheet-1");
var pasteSheet = ss.getSheetByName("My-Sheet-2");
var clearContentRange = pasteSheet.getRange("A1:Z100");
clearContentRange.clearContent();
var source = copySheet.getRange("a1:f100");
var destination = pasteSheet.getRange("a1:f100");
source.copyTo(destination, {formatOnly:true , contentsOnly:true});
source.copyTo(destination,SpreadsheetApp.CopyPasteType.PASTE_COLUMN_WIDTHS,false);
var rows = pasteSheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if (row[3] == '') {
var deleteRowNum = (parseInt(i)+1) - rowsDeleted
pasteSheet.deleteRow(deleteRowNum);
// temp_array[i] = i
rowsDeleted++;
}
}
pasteSheet.deleteColumn(2)
}
Hi,
I have written the following script to perform the following operations,
Copy data from My-Sheet-1 and paste to My-Sheet-2
Deletion of rows that corresponds to empty cells in column 3.
After that deletion of column 2
Rigthnow, the My-Sheet-1 contains only 60 rows and 20, the script is taking approximately 7 secs to complete. However in future the number of rows may extend to some 1000. Is there a way to optimize the above code, so that it takes less time to complete.
My observation is that, copy and pasting the data takes just milli secs. The major time consuming part are the operations, I am performing in the pasteSheet after pasting it. It may be helpful, if we can copy My-Sheet-1 to a temporary variable (copy everything including the formulas, format specifications, values, text etc..) and perform all operations in the temporary variable and then paste everything in the temporary variable to the desired target sheet. But, I don't know, how to copy everything in a sheet to a temporary variable, also, I am not sure, whether this will reduce the time or not. I would be glad, if I can get some help on this as well (i.e. copying everything in a sheet to a temporary variable, perfrom operations on the variables and then paste data in the variable to a new sheet)
Thank you
Edit - 1
Would like to add that, My-Sheet-1 contains mixed data (i.e. numerics, color formatted text, formulas in some cells etc)
Explanation:
deleteRow() takes some time per execution, so it's not recommended to use on hundreds of rows in a loop.
Simple answer would be:
Make a 2D array for Sheet1 using getValues().
Delete / filter out array elements depending if row2 is blank.
Use setValues() to write the filtered array into Sheet2.
Sample Code:
function dataManp() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("My-Sheet-1");
var pasteSheet = ss.getSheetByName("My-Sheet-2");
var lr = copySheet.getLastRow();
var clearContentRange = pasteSheet.getRange(1,1,lr,26);
clearContentRange.clearContent();
var source = copySheet.getRange(1,1,lr,6);
var destination = pasteSheet.getRange(1,1,lr,6);
source.copyTo(destination, {formatOnly:true , contentsOnly:true});
source.copyTo(destination,SpreadsheetApp.CopyPasteType.PASTE_COLUMN_WIDTHS,false);
destination.clearContent();
var values = source.getValues();
var temp_array = [];
for (var i = 0; i < lr; i++) {
var rowValue = values[i];
if (rowValue[2] != '') {
temp_array.push(rowValue);
}
}
var newDest = pasteSheet.getRange(1,1,temp_array.length,6)
newDest.setValues(temp_array);
pasteSheet.deleteColumn(2);
}
One caveat is that you need to have the same format for all rows in a column.
Sample Input:
Sample Output:

get x cell in range google sheets app script

Using a google sheets apps script, Is it possible to get the X cell in a range of cells as shown below:
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cells = sheet.getRange("D6:BF100"); // the range
for (var x = 0; x < 100; i++) {
var cell = cells[row][x]; // this is the line that doesn't work
if (someCondition(x)) {
cell.setBackground("red");
}
}
I don't want to change the colors for every single cell, just the ones that have the correct condition.
I know it is possible to do something like this:
var cell = sheet.getRange(row+i);
But this method takes a very long time to complete the for loop as there are hundreds of cells that need to be scanned. I would rather only use getRange once with the entire range (instead of just one cell at a time) and then from that range (it should make a 2d array right?) set the cell values. I think that would be a lot faster.
Is there a different way to do it faster, or do I just need to do this: var cell = cells[row][x]; a different way.
Thanks!
It looks like your for loop is constructed incorrectly. You increment the variable i that isn't defined or used anywhere. Also, you use the variable row without defining it.
It takes forever because it has to query your sheet each time you call cells.getRange() Instead, you can query once using cells.getValues() to get the whole range, and then change the cells color that meet the condition one at a time.
Try the following;
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cells_range = sheet.getRange("D6:BF100");
var cells_values = cells_range.getValues();
for (var col = 1; col <= cells_values[0].length; col++) {
for (var row = 1; row <= cells_values.length; row++) {
if (someCondition(cells_values[row][col])) {
cells_range.getCell(row, col).setBackground("red");
}
}
}
This is just my own answer to help users who might get to this question.
Once you have a range of cells, like this:
var range = sheet.getRange("your range");
You can do this to get a specific cell:
var cell = range.getCell(row, col);

Google Sheets: Those rows are out of bounds, can't figure out why

I've been piecing together a script to delete empty rows from a specific tab in a series of spreadsheets. It works up until the point it has to delete the rows, throwing a Those rows are out of bounds error. I followed this technique to delete the rows, which seems to have good results for others, so I'm having trouble figuring out why this isn't working.
I thought maybe it was that I was exceeding the number of deletable rows by 1, but tested that, and it didn't make a difference.
Any ideas? Thanks for the input!
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(2,3,17);
var values = range.getValues();
for (var row in values){
for (var col in values[row]) {
var theUrl = values[row][col];
var openTheUrl = SpreadsheetApp.openByUrl(theUrl);
Logger.log(openTheUrl.getName());
var currentSheet = openTheUrl.getSheetByName("Aggregate");
Logger.log(currentSheet.getName());
var maxRows = currentSheet.getMaxRows();
var lastRow = currentSheet.getLastRow();
var deleteRows = maxRows-lastRow;
if (maxRows-lastRow != 0){
sheet.deleteRows(lastRow+1, deleteRows);
}
}
}
}
In your script, I can understand as follows.
You want to delete rows using maxRows and lastRow retrieved from currentSheet opened by theUrl.
The rows that you want delete is in currentSheet.
If my understanding is correct, how about this modification?
From :
sheet.deleteRows(lastRow+1, deleteRows);
To :
currentSheet.deleteRows(lastRow+1, deleteRows);
If I misunderstand your question, I'm sorry.

Google Apps Script, spreadsheet, taking too long to run

I'm using an onEdit() function that checks which cell in which sheet has been changed to run the appropriated routine.
When the changed cell is in sheet1 and is not the I3 it should run a simple routine, but it is taking too long.
Here is the code:
if (sheet === 'sheet1'){
if (changedCell != 'I3') {
var row = e.source.getActiveRange().getRow();
var cont = row-6;
var column = e.source.getActiveRange().getColumn();
var Relatorio = ss.getSheetByName("RELATÓRIOS_ACOMPANHAMENTO");
var edit = Relatorio.getRange(row, column);
var coluna = Relatorio.getRange(5, column).getValue();
var linha = Relatorio.getRange(row, 15).getValue();
var baseAcom = ss.getSheetByName("EVENTOS_PARTICIPANTES");
var editbase = baseAcom.getRange(linha, coluna);
edit.copyTo(editbase, {contentsOnly: true});
}
}
When I check the spreadsheet, it does what i want to do very fast, but it stays showing the calculating formulas bar for almost 1 min, and I can't perform any other functions until it ends.
Is there a way for me to speed it up?

Google spreadsheet ImportRange - need to improve my workaround

I am pretty new to this forum and also to the google scripts. I have never actually learned JavaScript or any other programming language, however I was forced to start using then since the time I chose the google apps as my main platform for my small business.
My problem is in google ImportRange function limitation to 50 on every spreadsheet. I created a model, where every customer has his own spreadsheet with his personal data, deadlines, etc. located in his own folder in google drive.
I also created a spreadsheet called "Organizer", Organizer has two functions -
1) create automatic correspondention using autoCrat script,
2) show deadlines for every costumer and sort them by priority.
So i need to be able to share / import / copy data from all customer spreadsheets to the "Organizer". Because there are 50+ costumer spreadsheets, I had to give up on ImportRange function and instead of that I am using a simple script to copy files from every spreadsheet directly:
function ImportDataRange() {
// rown number.1
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Databaze");
var range = sheet.getRange(2, 1)
var id = range.getValue()
var ssraw = SpreadsheetApp.openById(id);
var sheetraw = ssraw.getSheetByName("Raw");
var range = sheetraw.getRange("A2:AB2");
var data = range.getValues();
sheet.getRange("B2:AC2").setValues(data)
// row number.2
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Databaze");
var range = sheet.getRange(3, 1)
var id = range.getValue()
var ssraw = SpreadsheetApp.openById(id);
var sheetraw = ssraw.getSheetByName("Raw");
var range = sheetraw.getRange("A2:AB2");
var data = range.getValues();
sheet.getRange("B3:AC3").setValues(data)
}
This script actually works well, but problem is, when I want to add new costumer spreadsheet to "Organizer" using this method, I have to manually add new copy of whole code for every new row and also change the output range of imported data and location of source file ID in "Organizer".
Does anybody know some kind of workaroud, which will help me to add new rows / costumer data easier / automatically ?
Thank you for your help!
You are going to want to use a loop of some sort. I haven't tested the code below, but based on your example, I think this should work for you.
function ImportOtherSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Databaze");
// Get the first column
// lastRow() - 1 because we're starting at row 2
var sheetIds = sheet.getRange(2, 1, sheet.getLastRow() - 1);
// For each ID in the id column
for (var i = 0; i < sheetIds.length; i++) {
var id = sheetIds[i]; // Get the id from the Array
// Get the new sheet, range and values
var ssraw = SpreadsheetApp.openById(id);
var sheetraw = ssraw.getSheetByName("Raw");
var range = sheetraw.getRange("A2:AB2");
var data = range.getValues();
// Get the local range, and write the values
sheet.getRange(i + 1, 2, 1, data[0].length).setValues(data)
}
}
As you learn more about GAS and JS, take advantage of MDN and the GAS Documentation
I took the fooby´s code and after long trial-and-error procedure I came with code that is working for me, so if anyone is interested, here it is:
function ShowDataFromOtherSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Databaze");
var ids = sheet.getRange(2, 1, sheet.getLastRow() - 1).getValues();
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
var ssraw = SpreadsheetApp.openById(id);
var sheetraw = ssraw.getSheetByName("Raw");
var range = sheetraw.getRange("A2:AB2");
var data = range.getValues();
sheet.getRange(i + 2, 2, 1, data[0].length).setValues(data)
}
}
And thank you fooby - i would not make it without your help!

Categories