JamesReed68
JamesReed68

Reputation: 419

Is there a way to optimize this script to run faster? I am getting the error "Exceeded maximum execution time"

I am using Google App Scripts to import data from Spreadsheet #1 to Spreadsheet #2. But I am getting the error "Exceeded maximum execution time". What am I doing wrong? Is there a better way to optimize the code?

Script Logic

Spreadsheet #1 (Source)

A B C D E F G H I J K L M N O P Q R S T U V W
200001 [email protected] [email protected]
200001 [email protected] [email protected]

Spreadsheet #2 (Destination)

Working Script (for data less than 5,000 rows).

// Source sheet settings
let sourceSheetId = '1qW5UDn0O*******************';
let sourceTab = 'Source';
let sourceColumn = 2;
let sourceEmail1Column = 20;
let sourceEmail2Column = 19;

// Destination sheet settings
let destinationTab = 'Destination';
let destinationColumn = 1;
let destinationEmail1Column = 2;
let destinationEmail2Column = 4;


function newEmployeeIds() {
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let destinationSheet = ss.getSheetByName(destinationTab);

  let sourceSS = SpreadsheetApp.openById(sourceSheetId);
  let sourceSheet = sourceSS.getSheetByName(sourceTab);

  let existingIdsArray = destinationSheet.getRange(2,destinationColumn,destinationSheet.getLastRow()-1,1).getValues();
  let existingIds = existingIdsArray.flat();

  let sourceIdArray = sourceSheet.getRange(2,sourceColumn,sourceSheet.getLastRow()-1,1).getValues();
  let sourceIds = [...new Set(sourceIdArray.flat())];

  let email1Array = sourceSheet.getRange(2,sourceEmail1Column,sourceSheet.getLastRow()-1,1).getValues();
  let email2Array = sourceSheet.getRange(2,sourceEmail1Column,sourceSheet.getLastRow()-1,1).getValues();

  for (i=0;i<sourceIds.length;i++){
    if (existingIds.indexOf(sourceIds[i]) == -1){
    let newRow = destinationSheet.getLastRow()+1;
    destinationSheet.getRange(newRow,destinationColumn).setValue(sourceIds[i]);
    let index = sourceIdArray.flat().indexOf(sourceIds[i]);
    destinationSheet.getRange(newRow,destinationEmail1Column).setValue(email1Array[index][0]);
    destinationSheet.getRange(newRow,destinationEmail2Column).setValue(email2Array[index][0]);
    }
  }

}

Upvotes: 2

Views: 91

Answers (1)

Tanaike
Tanaike

Reputation: 201388

I believe your goal is as follows.

  • You want to reduce the process cost of your script.

In this case, how about the following modification? In this modification, at first, the values are retrieved from the source and destination sheets, and create an array for putting to the destination sheet, and put it to the sheet.

Modified script:

function newEmployeeIds2() {
  const srcSheetName = 'Source';
  const dstSheetName = 'Destination';
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const [srcSheet, dstSheet] = [srcSheetName, dstSheetName].map(s => ss.getSheetByName(s));

  // Retrieve values from source sheet.
  const srcValues = srcSheet.getDataRange().getValues();

  // Retrieve values from destination sheet and create an object for searching the ID.
  const dstLastRow = dstSheet.getLastRow();
  const dstObj = dstSheet.getRange("A1:A" + dstLastRow).getValues().reduce((o, [a]) => (o[a] = true, o), {});

  // Create an array for putting to the destination sheet.
  const values = srcValues.filter(r => !dstObj[r[1]]).map(r => [r[1], "", r[18], r[19]]);

  // Put the values to the destination sheet.
  dstSheet.getRange(dstLastRow + 1, 1, values.length, values[0].length).setValues(values);
}

References:

Added:

From your following replying,

Unfortunately I am receiving the error "Cannot read property 'getDataRange' of null (const srcValues = srcSheet.getDataRange().getValues();)". I believe this is because your code assumes the source and destination sheet are in the same Spreadsheet. In reality, the source sheet is in a different spreadsheet. I tried changing const srcSheetName = 'Source'; to const srcSheetName = SpreadsheetApp.openById('1qW5UDn0O*******************').getSheetByName('Source'); but still an error when running the code. Do you know whats wrong?

From your replying, I modified the script as follows.

Modified script:

Before you run teh script, Please set the Spreadsheet ID1.

function newEmployeeIds2() {
  const srcSheetName = 'Source';
  const dstSheetName = 'Destination';
  const srcSheet = SpreadsheetApp.openById("SpreadsheetID1").getSheetByName(srcSheetName);

  const dstSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(dstSheetName);
  // or const dstSheet = SpreadsheetApp.openById("SpreadsheetID2).getSheetByName(dstSheetName);

  // Retrieve values from source sheet.
  const srcValues = srcSheet.getDataRange().getValues();

  // Retrieve values from destination sheet and create an object for searching the ID.
  const dstLastRow = dstSheet.getLastRow();
  const dstObj = dstLastRow == 0 ? {} : dstSheet.getRange("A1:A" + dstLastRow).getValues().reduce((o, [a]) => (o[a] = true, o), {});

  // Create an array for putting to the destination sheet.
  const values = srcValues.filter(r => !dstObj[r[1]]).map(r => [r[1], "", r[18], r[19]]);

  // Put the values to the destination sheet.
  dstSheet.getRange(dstLastRow + 1, 1, values.length, values[0].length).setValues(values);
}

Upvotes: 3

Related Questions