Code for retrieving information; some data may not be retrieved

I created a Google Sheets script that iterates through all rows and retrieves API data, then pastes the results in a column all at once. Everything was working fine until I started using the following code snippet instead of referencing a sheet name.

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();

Now, the script returns all the chunks it could fetch within the 5-minute runtime limit, then restarts with the next trigger and retrieves another chunk. This has significantly increased the duration of the script.

The initial solution I thought of was to create nested functions so that only the fetch part reruns and not the entire script (including loading the active sheet). However, I encountered an 'data is not defined' error which I believe might be due to the data being wiped every time the script terminates due to the Google time limit.

How can I solve this issue? Using `getActiveSheet()` is preferred as I want to be able to run this script from a button on two different tabs.

The section of code that is returning incomplete chunks (e.g., 80 rows instead of all 400 rows) is:

/** GLOBAL PARAMETERS */

  // Serp API key
  var API_KEY = '12345';

  // key columns
  var COL_DOMAIN = 2;
  var COL_QUERY = 3;
  var COL_RANK = 5;
  var COL_GL = 8;

/** END: GLOBAL PARAMETERS */



/** 
 * Main function: gets search ranks using the Serp API
 */
function getRank() {

  // start timer and delete active triggers
  var timeStart = new Date();
  deleteTriggers();

  // Spreadsheet and sheet
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();

  // get data from all rows in a 2-d array
  // array indices start at "0" instead of "1"
  // so to get row 1 it would be element 0 in the array and so on...
  var LR = sheet.getLastRow();
  var data = sheet.getRange(1, 1, LR, 18).getValues();

  // loop through all rows
  // starting at row = 3 (array element index = 2)
  for (var i = 2; i < data.length; i++) {

    console.log(i);

    // skip if processed before
    var row = data[i];
    if (row[COL_RANK - 1] != '') {
      continue;
    }

    // process row
    try {

      // get parameters
      var domain = row[COL_DOMAIN - 1];
      var query = row[COL_QUERY - 1];
      var goog = row[COL_GL - 1];
      var gl = goog;
      var hl = goog;
      if (gl == 'co.uk') {
        gl = 'uk'
        hl = 'en'
      }
      else if (gl == 'com') {
        gl = 'us'
        hl = 'en'
      }

      // send API request
      var url = 'https://serpapi.com/search'
        + '?q=' + encodeURIComponent(query)
        + '&gl=' + gl
        + '&hl=' + hl
        + '&output=rank:' + encodeURIComponent(domain)
        + '&google_domain=google.' + goog
        + '&num=100'
        + '&api_key=' + API_KEY;
      var rank = UrlFetchApp.fetch(
        url, 
        { 
          'muteHttpExceptions': false 
        }
      ).getContentText();

      // update sheet with result
      sheet.getRange(i + 1, COL_RANK).setValue(rank);
      sheet.getRange(1,2).setValue(Date());
      
      // sleep for X milli-seconds
      Utilities.sleep(1);

      // check timer
      if (isTimeUp(timeStart)) {
        addTriggers();
        return;
      }
    
    } 
    catch (error) {
    
      sheet.getRange(i + 1, COL_RANK).setValue("Check of url(kolom B), afgesproken positie(D) of land(H) ontbreekt");
      continue;
    
    }

  }

}


/**
 * Checks if script execution time has hit the limit
 * default = 5 minutes if the minutes parameter is not passed to the function
 */
function isTimeUp(timeStart, minutes=5) {

  var now = new Date();
  return now.getTime() - timeStart.getTime() > minutes * 60 * 1000;

}

/**
 * Sets up a time trigger for the function to run in one minute
 */
function addTriggers() {

  //delete active triggers
  deleteTriggers();

  //create new trigger
  ScriptApp.newTrigger('getRank')
    .timeBased()
    .after(60 * 1000)
    .create();

}

/**
 * Deletes active triggers
 */
function deleteTriggers() {

  var triggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < triggers.length; i++) {

    ScriptApp.deleteTrigger(triggers[i]);

  }

}

Answer №1

A straightforward solution has been discovered. It appears that using activesheet does not interact well with generating triggers. As a result, the trigger for rerunning the script after a timeout fails to execute.

I have resolved this issue by storing the active sheet's name in a variable and passing it on to getSheetByName like so. This adjustment now allows the script to function properly across multiple sheets:

var name = ss.getActiveSheet().getName();
var sheet = ss.getSheetByName(name);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I'm looking for a method to retrieve the value of an option tag and then pass it to a helper within handlebars. Can someone

Currently, I am utilizing express and handlebars in my project. I have a specific view where I aim to display certain information based on the event when a client selects an option from a select tag. However, I have some queries regarding this: Is it fea ...

Variety of part ingredients

In my component, I have a button and include another component which also contains a button. How can I align these two buttons next to each other without using absolute positioning? When I try positioning them using absolute right and top values, the lay ...

Creating an X pattern on an HTML5 canvas and detecting intersections with a perimeter

I am currently developing a maze game using HTML 5. Below is the function I have implemented to draw an "X" on the canvas (the player will guide the X through the maze using touchpad). dim = 8; function rect(x,y,xdim){ ctx.beginPath(); ctx.moveT ...

Ways to control the number of boxes that are checked

I am currently working on a script to restrict the number of checkboxes that can be checked, but I am encountering an issue where the script is disabling all checkboxes on the page. Is there a way to only disable a specific checkbox within a certain div? ...

Tips for distinguishing between elements in React

I am facing an issue with zooming images on mouse hover using CSS. I have a code snippet that works well, but it zooms both images simultaneously. How can I differentiate between mouse movements over different elements in ReactJS? Here is the code: .styl ...

Run JavaScript code whenever the table is modified

I have a dynamic table that loads data asynchronously, and I am looking for a way to trigger a function every time the content of the table changes - whether it's new data being added or modifications to existing data. Is there a method to achieve th ...

What is the significance of having nodejs installed in order to run typescript?

What is the reason behind needing Node.js installed before installing TypeScript if we transpile typescript into JavaScript using tsc and run our code in the browser, not locally? ...

The object in three.js disappears from the scene but remains visible

I am attempting to showcase text as a sprite in three.js and aim to move the sprite along with an object. I achieve this by utilizing a canvas to generate a texture, which is then mapped using SpriteMaterial to create a sprite from it. However, when I remo ...

Is there a way to incorporate page animations when utilizing the <a href> tag in HTML?

I have created several HTML files. On the main page, I simply inserted some code like this: <a href="new.html> <img src="img/button" id="buttonid"> </a> When I click the button, it takes me to the new.html page. I would like ...

Unable to pass on error from Express server to React client app

Background Overview In my project, I've implemented a React component named 'Register.jsx' where users can input their desired username and password. Upon clicking the submit button, this information is transmitted to an Express backend whi ...

Access information through the restful api using the angularjs service $resource

I am attempting to utilize the $resource service with the surveygizmo API. Here is my code: HTML : <div ng-app="Survey"> <body> <div ng-controller="SurveyCtrl"> {{survey.data.title}} </div> </body> </div> My scr ...

NodeJS - The function app.listen is not defined in this context

I've come across a similar question before, but the answers provided didn't help me resolve my issue. The error message I'm getting is "TypeError: app.listen is not a function"; Here's my full code below. Thank you in advance for your ...

Errors in TypeScript are being brought up by using if-else statements inside a loop

I am currently working on a function to retrieve referral codes from users. The user inputs a code, which is then checked against the database to see if it exists or not If the code provided matches the current user's code, it should not be accept ...

Is there a way for me to retrieve SCSS color variables within the javascript of a Vue template?

I have a unique challenge in my application involving a component called Notification. To bring notifications to other components, I utilize the mixin method toast('message to display', 'color-variable'). My goal is to set the backgroun ...

Leveraging React Native to position a view absolutely in the center of the screen without obstructing any other components

How can I center an image inside a view in the middle of the screen using position: "absolute"? The issue is that the view takes up 100% of the width and height of the screen, causing all components underneath it (such as input fields and buttons ...

Always keep your phone in landscape orientation for optimal website viewing

Currently, I am facing an issue with my website where it functions perfectly on mobile devices in landscape orientation but elements get distorted when viewed in portrait mode. Is there a method to ensure that the website is always displayed in landscape ...

Is it possible for Node.js to not automatically restart the server when modifying .js files?

Right now I have node-supervisor set up to detect changes in .js files, and while it works well, I've realized that it restarts the server every time a js file is saved. Is there a way to save a server-side .js file without triggering a server restart ...

HTML/JavaScript - Ways to show text entered into an input field as HTML code

One dilemma I'm facing involves a textarea element on my website where users input HTML code. My goal is to showcase this entered HTML code in a different section of the webpage. How should I approach this challenge? The desired outcome is similar to ...

Changing json into another format

I am struggling with a JSON data format issue. I have tried using Object.values and object.keys along with Array.prototype.map(), but my algorithm is not producing the desired outcome. [ { "2018-01-01": [ { "firstname": "mati", "lastname": "mati ...

Encountering a hydration issue with an SVG element embedded within a Link component in Next

I'm encountering a hydration error related to an icon within a link, Here is the error message: Error: Hydration failed because the initial UI does not match what was rendered on the server. Warning: Expected server HTML to contain a matching <svg ...