Long Polling / Data Changed Event for Google Sheets

INTRO

A while ago I did some work on creating a dataChanged event for a php TinyWebDB, I have now worked up a similar solution for a google sheet. This is of benefit for apps with multiple users who may be working on the same dataset in google sheets, all other users will need to be made aware of any changes, and to update their data. 

How this works:


There are two methods that can be used in the script:

Regardless the developer will probably want to return a new set of data to the app if there have been changes

The demo blocks and scripts below will return simple text content as opposed to a full dataset, for demonstration purposes.


Note: I am aware of the getLastUpdated() function that is available in DriveApp, but this proved to be unreliable and was taking up to 2 minutes to report a change. There is also a method using Drive.Revisions, which looks at the last revision date. This works, but extra effort is needed when the number of revisions goes past the 1000 mark.

SCRIPTS

Comparing Arrays


function doGet() {

 var ss = SpreadsheetApp.openById('fileID');

 var sh = ss.getSheetByName('SheetName');

 var rng = sh.getDataRange().getValues();

 var msg = '';


 for (var i = 0; i < 20; i++) {

   SpreadsheetApp.flush();

   var cur = sh.getDataRange().getValues();

   i = i + 1;

   if (JSON.stringify(rng) !== JSON.stringify(cur)) {

     msg = 'Data has changed';

     return ContentService.createTextOutput(msg);

   }

   Utilities.sleep(10000);

 }

 return ContentService.createTextOutput(msg);

}



Comparing modifiedDate

(You need to enable the Drive API in Services for this to work)


function doGet() {


 var lastUpdated = Drive.getFileById('fileID').modifiedDate;

 var msg = '';


 for (var i = 0; i < 20; i++) {

   var curUpdate = Drive.getFileById('fileID').modifiedDate;

   i = i + 1;

   if (lastUpdated.toString() !== curUpdate.toString()) {

     msg = lastUpdated.toString() + "\n" + curUpdate.toString();

     return ContentService.createTextOutput(msg);

   }

   Utilities.sleep(10000);

 }

 return ContentService.createTextOutput(msg);

}


You should be able to see that the scripts are set to run 20 times, every 10 seconds = @ 3 minutes. This well within Google's execution time limit. Developers can adjust the values to their liking. Developers should be aware of possible quota issues for a large number of users / high number of script executions.

BLOCKS

ADDITIONAL

You may want to return just the records (rows) that have changes in them. Here is a google apps script function that can do that, would need to be combined with the above scripts. This may take some time to work through a large dataset....:



 var changes = [];

 for (var k = 0; k < rng.length; k++) {

  if (JSON.stringify(rng[k]) !== JSON.stringify(cur[k]))

     changes.push(cur[k]); 

     } 

  }

 msg =  changes;


You will need to grab the data arrays if using the Drive.modifieddate method