Home > database >  Minimize Call to other service - optimisation of my code to avoid Exceeded maximum execution time
Minimize Call to other service - optimisation of my code to avoid Exceeded maximum execution time

Time:06-18

I have this code that extracts calendars from a list of Google calendars. I have a problem with the maximum execution time.

function export_gcal_to_gsheetLast1(){
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Extraction 1 - Calendrier");
  var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Id Calendriers - Dates Debut et Fin"); //Sheet name where you will have the list of calendar ID's, startDate and endDate

  sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
  // other option would be to create a script to check if data already exists before adding it to the sheet

  // Set filters
  var startDate = sheet2.getRange('k1').getValue(); //Range for startDate
  var endDate = sheet2.getRange('k2').getValue(); //Range for endDate
  var users = sheet2.getRange('b3:B').getValues(); //Range where you have the calendar ID's

  // Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
  // of the getRange entry below
  var header = [["Titre", "Description", "Location", "Début", "Fin", "Heures effectives","Extraction 2","Extraction 3","Heures Planifiées", "Vacances", "Maladie","Congé légal", "Absence"]]
  var range = sheet.getRange(7,1,1,13);
  range.setValues(header);
  
  for (var j = 0; j< users.length; j  ){
    //here we do the things we do once per calander
    if (users[j] == ""){
      break;
    }
    
    else{
      var cal = CalendarApp.getCalendarById(users[j]);
      var events = cal.getEvents(startDate, endDate);

      // Loop through all calendar events found and write them out starting on the next empty row
      for (var i=0;i<events.length;i  ) {
        var myformula_placeholder = '';
        var details=[
          [events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), 
          myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder]
        ];

        var lastRow = sheet.getLastRow() 1;
        var range=sheet.getRange(lastRow,1,1,13);
        range.setValues(details);


        let formulas = []
        for(let i = 0; i < 7; i  ){formulas.push('=(HOUR(RIGHT(b'  lastRow ';5)) (MINUTE(RIGHT(b'  lastRow  ';5))/60))-(HOUR(LEFT(b'  lastRow  ';5)) (MINUTE(LEFT(b'  lastRow  ';5))/60))')}}
        sheet.getRange(lastRow,6).setFormulas(formulas)

        //var cell=sheet.getRange(lastRow,6);
        //cell.setFormula('=(HOUR(RIGHT(b'  lastRow ';5)) (MINUTE(RIGHT(b'  lastRow  ';5))/60))-(HOUR(LEFT(b'  lastRow  ';5)) (MINUTE(LEFT(b'  lastRow  ';5))/60))')
        cell.setNumberFormat('.00');
        
        var cell=sheet.getRange(lastRow,7);
        cell.setFormula('=IFERROR(TEXT(INDEX(SPLIT(A' lastRow ';" ");2);"hh:mm");"")')
        
        
        var cell=sheet.getRange(lastRow,8);
        cell.setFormula('=IFERROR(TEXT(INDEX(SPLIT(A' lastRow ';" ");3);"hh:mm");"")')

        var cell=sheet.getRange(lastRow,9);
        cell.setFormula('=IF(OR(G' lastRow '="Maladie";G' lastRow '="Congé";G' lastRow '="Absence";G' lastRow '="00:00";G' lastRow '="Vacances");0;(HOUR(H' lastRow ') (MINUTE(H' lastRow ')/60))-(HOUR(G' lastRow ') (MINUTE(G' lastRow ')/60)))')

        var cell=sheet.getRange(lastRow,10);
        cell.setFormula('=IF(IFNA(VLOOKUP(D' lastRow '; feries;1;FALSE);1)<>1;0;IF(AND(G' lastRow '="00:00";H' lastRow '="Vacances");0.5;IF(G' lastRow '="Vacances";1;0)))')

        var cell=sheet.getRange(lastRow,11);
        cell.setFormula('=IF(G' lastRow '="Maladie";1;0)')

        var cell=sheet.getRange(lastRow,12);
        cell.setFormula('=IF(G' lastRow '="Congé";1;0)')
        
        var cell=sheet.getRange(lastRow,13);
        cell.setFormula('=IF(G' lastRow '="Absence";1;0)')

      }
    }
  }

One of the problems is that I'm using methods like setFormula or getRange inside of a loop, this causes a massive call to Spreadsheet service.

This is not recommended by the best practices guides Minimize Call to other service.

So, in order to solve this problem I have to use another recommendation from Best Practices guide, using batch operation.

Instead of using setFormula use setFormulas and delegate to Javascript all the tasks to build the formulas.

I have recived this advice: All the lines that start with: var cell=sheet.getRange(lastRow,6); cell.setFormula('=(HOUR(RIGHT(b' lastRow ';5)) (MINUTE(RIGHT(b' lastRow ';5))/60))-(HOUR(LEFT(b' lastRow ';5)) (MINUTE(LEFT(b' lastRow ';5))/60))')

Should move to something like that: let formulas = [] for(let i = 0; i < 7; i ){formulas.push(FORMULAS)} sheet.getRange(x,y,nx,ny).setFormulas(formulas)

I have try to change my code using this but without success. Can someone please give me an example using my code on how I can do this change ? Thanks a lot !!

CodePudding user response:

You create arrays and push the data in there. Then like you said, you can bulk update it all. Would be something like below. I did not test it and maybe the range is off. But this will get you in the right direction.

function export_gcal_to_gsheetLast1(){
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Extraction 1 - Calendrier");
  var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Id Calendriers - Dates Debut et Fin"); //Sheet name where you will have the list of calendar ID's, startDate and endDate

  sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
  // other option would be to create a script to check if data already exists before adding it to the sheet

  // Set filters
  var startDate = sheet2.getRange('k1').getValue(); //Range for startDate
  var endDate = sheet2.getRange('k2').getValue(); //Range for endDate
  var users = sheet2.getRange('b3:B').getValues(); //Range where you have the calendar ID's

  // Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
  // of the getRange entry below
  const data = []
  const formulas = [];
  const headers = [["Titre", "Description", "Location", "Début", "Fin", "Heures effectives","Extraction 2","Extraction 3","Heures Planifiées", "Vacances", "Maladie","Congé légal", "Absence"]]

  
  for (var j = 0; j< users.length; j  ){
    //here we do the things we do once per calander
    if (users[j] == ""){
      break;
    }
    
    else{
      var cal = CalendarApp.getCalendarById(users[j]);
      var events = cal.getEvents(startDate, endDate);

      // Loop through all calendar events found and write them out starting on the next empty row
      for (var i = 0; i < events.length; i  ) {
        var details=
        [
          events[i].getTitle(), 
          events[i].getDescription(), 
          events[i].getLocation(), 
          events[i].getStartTime(), 
          events[i].getEndTime()
        ];

        data.push(details);
        const rowFormulas = 
        [
          '=(HOUR(RIGHT(b'  lastRow ';5)) (MINUTE(RIGHT(b'  lastRow  ';5))/60))-(HOUR(LEFT(b'  lastRow  ';5)) (MINUTE(LEFT(b'  lastRow  ';5))/60))',
          '=IFERROR(TEXT(INDEX(SPLIT(A' lastRow ';" ");2);"hh:mm");"")',
          '=IFERROR(TEXT(INDEX(SPLIT(A' lastRow ';" ");3);"hh:mm");"")',
          '=IF(OR(G' lastRow '="Maladie";G' lastRow '="Congé";G' lastRow '="Absence";G' lastRow '="00:00";G' lastRow '="Vacances");0;(HOUR(H' lastRow ') (MINUTE(H' lastRow ')/60))-(HOUR(G' lastRow ') (MINUTE(G' lastRow ')/60)))',
          '=IF(IFNA(VLOOKUP(D' lastRow '; feries;1;FALSE);1)<>1;0;IF(AND(G' lastRow '="00:00";H' lastRow '="Vacances");0.5;IF(G' lastRow '="Vacances";1;0)))',
          '=IF(G' lastRow '="Maladie";1;0)',
          '=IF(G' lastRow '="Congé";1;0)',
          '=IF(G' lastRow '="Absence";1;0)'
        ]
        
        formulas.push(rowFormulas)

      }
    }
  }

  sheet.getRange(7,1,1,headers.length, headers[0].length).setValues(headers)
  sheet.getRange(8,1,data.length,data[0].length).setValues(data);
  sheet.getRange(8,data[0].length   1,formulas.length, formulas[0].length).setFormulas(formulas);
  sheet.getRange(8,6,sheet.getLastRow()).setNumberFormat('.00');

}

CodePudding user response:

Thank you again to RemcoE33 for his code. I fixe two mistakes, lastrow was missing and the getRange had an error. Now it is working very well. Thanks a lot !!

  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Extraction 8 - Calendrier");
  var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Id Calendriers - Dates Debut et Fin"); //Sheet name where you will have the list of calendar ID's, startDate and endDate

  sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
  // other option would be to create a script to check if data already exists before adding it to the sheet

  // Set filters
  var startDate = sheet2.getRange('k15').getValue(); //Range for startDate
  var endDate = sheet2.getRange('k16').getValue(); //Range for endDate
  var users = sheet2.getRange('b3:B').getValues(); //Range where you have the calendar ID's

  // Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
  // of the getRange entry below
  const data = []
  const formulas = [];
  const headers = [["Titre", "Description", "Location", "Début", "Fin", "Heures effectives","Extraction 2","Extraction 3","Heures Planifiées", "Vacances", "Maladie","Congé légal", "Absence"]]

  
  for (var j = 0; j< users.length; j  ){
    //here we do the things we do once per calander
    if (users[j] == ""){
      break;
    }
    
    else{
      var cal = CalendarApp.getCalendarById(users[j]);
      var events = cal.getEvents(startDate, endDate);
      var lastRow = sheet.getLastRow() 8;

      // Loop through all calendar events found and write them out starting on the next empty row
      for (var i = 0; i < events.length; i  ) {
        var details=
        [
          events[i].getTitle(), 
          events[i].getDescription(), 
          events[i].getLocation(), 
          events[i].getStartTime(), 
          events[i].getEndTime()
        ];

        data.push(details);
        const rowFormulas = 
        [
          '=(HOUR(RIGHT(b'  lastRow ';5)) (MINUTE(RIGHT(b'  lastRow  ';5))/60))-(HOUR(LEFT(b'  lastRow  ';5)) (MINUTE(LEFT(b'  lastRow  ';5))/60))',
          '=IFERROR(TEXT(INDEX(SPLIT(A' lastRow ';" ");2);"hh:mm");"")',
          '=IFERROR(TEXT(INDEX(SPLIT(A' lastRow ';" ");3);"hh:mm");"")',
          '=IF(OR(G' lastRow '="Maladie";G' lastRow '="Congé";G' lastRow '="Absence";G' lastRow '="00:00";G' lastRow '="Vacances");0;(HOUR(H' lastRow ') (MINUTE(H' lastRow ')/60))-(HOUR(G' lastRow ') (MINUTE(G' lastRow ')/60)))',
          '=IF(IFNA(VLOOKUP(D' lastRow '; feries;1;FALSE);1)<>1;0;IF(AND(G' lastRow '="00:00";H' lastRow '="Vacances");0.5;IF(G' lastRow '="Vacances";1;0)))',
          '=IF(G' lastRow '="Maladie";1;0)',
          '=IF(G' lastRow '="Congé";1;0)',
          '=IF(G' lastRow '="Absence";1;0)'
        ]
        
        formulas.push(rowFormulas)
        lastRow=lastRow 1
      }
    }
  }

  sheet.getRange(7,1,headers.length, headers[0].length).setValues(headers)
  sheet.getRange(8,1,data.length,data[0].length).setValues(data);
  sheet.getRange(8,data[0].length   1,formulas.length, formulas[0].length).setFormulas(formulas);
  sheet.getRange(8,6,sheet.getLastRow()).setNumberFormat('.00');

}```
  • Related