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

Loading elements of a webpage in a consecutive order

I am currently working on implementing a content slider within my Django application. The specific slider that I am using can be found at this link. One challenge that I am facing is the need to load close to one hundred 'contentDiv' pages, and I ...

Unforeseen behavior in Ajax success callback

My unordered list contains a href link. Initially, only the welcome page is visible on page load. Upon clicking the list for the first time after page load, the desired results are displayed in the corresponding div as expected. The issue arises when swi ...

Failing to send contact information using JSON in PHP

I attempted to transmit JSON data to PHP for email processing, but encountered an issue where the process veered into the 'else' condition during debugging. Here is the code snippet: HTML <form id="cbp-mc-form" class="cbp-mc-form" method="po ...

The checkbox is displayed as selected after being clicked in conjunction with another checkbox

In the tree structure, there are checkboxes that behave strangely when clicked. I have already read a similar discussion here. The problem I am encountering is that when I click on an item, it gets checked but the console does not show it as checked immed ...

How can we effortlessly generate a times table using For loops and arrays?

As someone new to JavaScript, I am eager to learn. My goal is to create two "for" loops: one to save the values of the 6 times table up to 12x6 into an array called timesTable, and another to display these values in the console (e.g., 0 x 6 = 0). Thank y ...

When the return false statement is included, the form fails to submit and instead refreshes on the current page

I recently discussed an issue regarding triggering a dialog box before confirming a submit action. Unfortunately, after implementing this, the document no longer submits when expected. Instead, it just remains on the same page with the same settings. I h ...

Is there a way to make a string evaluate inline using JavaScript and React?

In my function, the following code works perfectly: console.log(theme.colors.blues[1]); To make the last part dynamic, I tried the following approach: const getColor = (theme, passedColorProp) => { console.log(theme.colors.[passedColorProp]); }; g ...

Ways to simulate a constant that acts as a dependency for the service being examined?

I'm currently experimenting with a file named connect-key.js. It relies on a dependency called keyvault-emulator. Content of File #1: // connect-key.js file const { save, retrieve, init } = require('./keyvault-emulator') .... .... .... // ...

Angular.js hierarchical model issue: grandchildren functionality not functioning as expected

Currently, I am delving into the world of Angular and exploring its functionalities. My main goal is to construct a hierarchical data structure that can be easily manipulated using a hierarchical view: Root: - addChild - child 1: { remove, addChild, c ...

using angularjs to dynamically apply css styles

Below is the input I have: The HTML code is shown below: <input type="number" ng-class="{negative: amount < 0}" ng-model="amount"/> This is the corresponding CSS code: .negative { color: red; } If the amount is positive, no specif ...

Having trouble utilizing the DatePicker component in my react native application

I've encountered an issue while using DatePicker in react native. Whenever I try to use it, an error pops up saying: "render error a date or time must be specified as value prop". Here is the link to my repository: my github repository const [date, se ...

Personalized parameters in communication for Quickblox's JavaScript

Sending a chat message with custom parameters to the Quickblox API involves specifying various details such as the body of the message, date sent, dialog ID, and more. For example: message: { body: 'something', date_sent: 'some date&apo ...

The principle of event delegation in jQuery

Are event handlers delegated across both <div> tags? In other words, is there one or two event handlers being used? I'm looking to extract the data-id from the event.delegateTarget. It's straightforward when attached to each of the <div& ...

Transferring data from local storage to a PHP server using AJAX

My attempt to transfer data from local storage to PHP using AJAX resulted in an error mentioning 'undefined index data'. chart.php <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script type="t ...

Tips on choosing and retrieving the value of filled text area fields using jQuery

I am struggling with selecting non-empty textareas and retrieving their values using jQuery. Here is a snippet of my code: <div class="item"> <textarea class="col-sm-10 comment">TextArea1</textarea> </div> <d ...

What is the best way to incorporate personalized events into an array using JavaScript?

Imagine we have an array called var arr = [1, 2, 3]. I am looking for a way to create a method that can observe any changes made to this array. The idea is something similar to the following: arr.on('change', function () { // perform some ac ...

What is the best way to deactivate the time-based trigger in an old version of a Google sheet, while ensuring it remains active in the duplicated new version?

When I initially copied a Google Sheet, I assumed that the app scripts would be duplicated as well. However, it turns out that this is not the case. Here's the background story: I made a version 2 by copying version 1. Because I wanted to ensure that ...

GraphQL query excluding empty fields for various types of objects

Utilizing Apollo Graphql, I attempted to employ inheritance for retrieving various types of models without success. My goal is to extract specific fields from the objects while omitting those that are unnecessary. To address the issue of incomplete object ...

In PATCH requests, JSON data is not transmitted through Ajax

I'm attempting to send JSON data from the client to my server with the following code: $.ajax({ url : 'http://127.0.0.1:8001/api/v1/pulse/7/', data : data, type : 'PATCH', contentType : 'application/json' ...

When trying to authorize my channel, the JSON data is coming back as a blank string

I've encountered an issue with my JavaScript code: Pusher is throwing the error message "JSON returned from auth endpoint was invalid, yet status code was 200. Data was: ", indicating empty data. I have double-checked the broadcasting service provider ...