Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Apps Script Iterating over Spreadsheets very slow

First time posting, long time reading :)

I've just written my first google apps script to collate information from 14 spreadsheets, each sheet with 2-30 worksheets into a single report spreadsheet.

The script runs beautifully, it checks a single column for data and if found grabs the spreadsheet name, worksheet name, first column data for the row and the data from the check column and adds it to an array as a sub-array of data.

It then calculates the area of the array of sub-arrays and writes the data into the report file (which is where the script is run from).

My only issue is that it takes the script around 2 minutes to run.

I wonder if I've been inefficient in my method and was hoping someone could review the script and let me know if I've made some mistakes?

here goes:

/**
* Retrieves all the rows in the active spreadsheet that contain data and logs the
* values for each row.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/

function getFaults() {
/** opens each spreadsheet for Liddon and examines the "Report/Replace" column "F"
if there is data there then  get the 
[Sheetname], [fault area (column "A" row relative to the "F" field found)] and the ["F" field  data]
 **/
var reportsheet = SpreadsheetApp.getActiveSheet();
var reportdata = []
var reportrow = 0

var liddonblocks = [ 
"1APshQevK7iZxhP7--zmtuM3K6dPTgTZjmNarQ6CEsV4", "1riCQMOa38jo4nCD4qjW1BFZKk5xpXFZiCXHzXpiYKIU",   "1NTKXmted1-U12MiqvCGRuYBdhPy1_eLiPn7v8_oVKFE", "1RKOJUNNi5TAg5dETZDtLjZOkUSheuguzmtdPelMclMI",
"1b5-fzCp0wzW8llpUc_6xi1iTFzsapZh9ASSFgDYt4WU", "1qJtY37K0zwoJcz7LdyHhWgkypRMP9LabBchNLM4Fgow",   "1yvf4W8-SkfTH-n-PdDNQeyEDEz-shzTe-Id57S_YB2M", "1ETZc1xeNGXU6ipb1XQiD8SiIyRXzZtiJfS4AClKroJk",
"1tJ5u3Hv0uz-n2cdw-QYixKnuMG9skvrUbz1UROhIm34", "1DjhmIdD0GrPxR-fv7pCPkIwIyfai5BHsK9GhT-Hcs3k", "15w39NZZIacD1OfiTWG1E3HmOhV0B_e2Jsuan_ySwf2Q" , "1cK2HBLEftYOZEkCcxs1TX1PxcJRiKTZpQrcsOfE4B1s",
"16W_bfMKk98wkLpEmm2Q68Ta_SrCA8EBarQyGF2yfm18","1_Z_tgF5UAfq3fxPsDEe40z2GZSehhL-u4hEuVszrbn8" ]

// loop through the spreadsheets
for (block = 0; block < liddonblocks.length; block++) { 
  //open the spreadsheet using the index from the liddonblocks list
  var ss = SpreadsheetApp.openById(liddonblocks[block]);
  //get all of the sheets within the spreadsheet
  var sheets = ss.getSheets();

//loop through each sheet in each spreadsheet using the length of the number of sheets in the     spreadsheet as the index
for (var sheetnum = 0; sheetnum < sheets.length; sheetnum++) {
  //get an array of all data in the sheet
  //assigns array in the form of: [[area, fault], [Bedroom, Broken Bed], [Bathroom, ]] 
  //where each sub-array is a row of data starting at row 1 eg: [[row1-col1, row1-col2...],[row2-col1, row2-col2...]...]
  data = sheets[sheetnum].getDataRange().getValues();
  //get the text name of the sheet
  name = sheets[sheetnum].getSheetName();

  // iterate over the data set and look for values in the  5th column, starting at row 7 to exclude the headers.
  // this is the column named "Report / Replace "
  for (var count = 7; count < data.length; count++) {
    if (data[count][5] != "" && data[count][5] != 0) {
      //if there is data in the 5th column of the row then append the following data to the reportdata array and a sub-array
      // [ sheetname, columnA, columnF ]
      reportdata[reportrow] = [ ss.getName(), name, data[count][0], data[count][5]]
      //increment the reportcount variable so any further hits on data in column 5 are created as sequentail sub-arrays in the reportdata array.
      reportrow++
    }
  }
}
}
//write the contents of reportdata to the console
var range = reportsheet.getRange(2,1,reportrow,reportdata[0].length);
range.setValues(reportdata);
}

/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var entries = [{
  name : "Update Report",
  functionName : "getFaults"
 }];
 spreadsheet.addMenu("Keble Scripts", entries);
};
like image 923
Random Chappy Avatar asked Nov 27 '14 08:11

Random Chappy


People also ask

Why is my Google sheet running so slow?

As your browser stores more cache and cookies, it could slow down. Clearing the cache and cookies can fix issues with items taking longer to load. See Clear cache & cookies. Browser extensions and plugins can sometimes cause issues with Google Docs, Sheets, Slides, or Forms.

How do you speed up a Google spreadsheet script?

Use batch operations Alternating read and write commands is slow. To speed up a script, read all data into an array with one command, perform any operations on the data in the array, and write the data out with one command.

How do I increase execution time in Google script?

You can register early access for App Maker after App maker enabled your script run runtime will increase run time from 6 minutes to 30 minutes :) Ya we can increase run time from 6 minutes to 30 minutes using Early access program but those apps cannot be deployed to public.

Does Google App script work in Excel?

The backbone part of this project is Google Apps Script which handles excel files, converts to the proper format, storages data then report our data. Google Apps is a good environment to run Google-based products like Gmail, Google Drive, Google Documents, Bigquery and more.


1 Answers

First of all, review the information on this page.

Three things I've experienced that can really slow you down are:

  1. Calling external service multiple times
  2. Calling SpreadsheetApp.flush() in a loop to force updating the sheet.
  3. Calling Range.getValue() a lot.

For the first part, try batching your calls. For instance if you are requesting exchange rates for your local currency and foreign ones, try sending a bunch of queries in one request.

For the second part, just don't call this method unless its really necessary.

for the third part, try modifying your code so you can call this method once and move around with its result instead of calling it in multiple methods for the same result.

Hint: To avoid modifying many methods parameters, just pass a single object at the beginning of your method-tree call and fill it with your parameters. This way you don't have to modify each method you pass by to add\remove a parameter. That's a concept that's applied to all programming languages with functions.

like image 172
Muhammad Gelbana Avatar answered Nov 02 '22 05:11

Muhammad Gelbana