首页 > 解决方案 > 使用 Google Apps Script Web App 轮询 Google 表格以进行更改的最佳方法?

问题描述

我正在开发一个谷歌应用程序脚本网络应用程序,以使其轮询谷歌表以进行更改/更新。目前,这可以是“内容”,也可以只是上次更新工作表的时间。我不能使用 gui/浏览器进行交互,因此请考虑运行 Web 应用程序的命令来自命令行上的 curl,并将文本内容返回到相同的内容。用户将根据需要重新启动 Web 应用程序,该应用程序设置为运行 @ 3 分钟。

我有一个有效的基本例程:

  1. 当应用程序启动时检查/获取原始状态(日期/内容)
  2. 运行一个计数器(每个)和一个计时器(睡眠),并在每次迭代中检查/获取当前状态(日期/内容)
  3. 在每次迭代中,针对当前状态测试原始状态。如果这些不同,则通过 ContentService 发送文本输出(消息、日期或当前内容。

我找到了三种适用于上述基础例程的方法:

A. 以数组形式获取工作表 dataRange 值 (sh.getDataRange().getValues();)

B. 获取 DriveApp LastUpdated 值 (DriveApp.getFileById(fileId).getLastUpdated();)

C. 获取修订列表最后修改日期(revisions = Drive.Revisions.list(fileId))

A效果很好,可以针对电子表格上的特定网格(工作表),但是对于大型数据集可能会出现问题?

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 = JSON.stringify(cur);
      return ContentService.createTextOutput(msg);
    }
    Utilities.sleep(10000);
  }

  return ContentService.createTextOutput(msg);

}

B 确实有效,但您似乎必须等待 1 到 5 分钟才能报告工作表上的更新。这“可能”没问题,但是对于进行更改的用户来说,它不够快

function doGet() {

  var lastUpdated = DriveApp.getFileById(fileId).getLastUpdated();
  var ss = SpreadsheetApp.openById(fileId);
  var sh = ss.getSheetByName('Sheet2');
  var rng = sh.getDataRange().getValues();
  var msg = '';

  for (var i = 0; i < 20; i++) {
    SpreadsheetApp.flush();
    var curUpdate = DriveApp.getFileById(fileId).getLastUpdated();
    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);

}

C 运行良好,几乎立即报告日期更改。不过,我有担心,读到1000 次修订后需要一个新令牌

function doGet() {
  
  var msg = '';
  var revisions = Drive.Revisions.list(fileId);
  var revision = revisions.items[revisions.items.length - 1];
  var date = new Date(revision.modifiedDate);
  
for (var i = 0; i < 20; i++) {
  
    var currevs = Drive.Revisions.list(fileId);
    var currev = currevs.items[currevs.items.length - 1];
    var curdate = new Date(currev.modifiedDate);
    
    i = i + 1;
    
    if ( date.toString() !== curdate.toString() ) {
      msg = date.toString() + "\n" + curdate.toString();
      return ContentService.createTextOutput(msg);
    }
    Utilities.sleep(10000);
  }

  return ContentService.createTextOutput(msg);

}

使用 B 是有意义的,但我找不到让 getLastupdated 的响应更直接的方法,也许是 C,使用修订是要走的路吗?我是否为此错过了“转到”方法,或者我的 Web 应用程序例程是否需要改进?

根据@Diego 的建议,我还通过 Advanced Drive Service 尝试了“modifiedDate”。这是一种享受:)

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);

}

标签: google-apps-script

解决方案


我看到在文件上使用修改日期与最新版本之间的区别在于,该文件还将报告对绑定脚本的更改。修订将仅限于电子表格上的更改并排除脚本更改。这可以在我下面的测试中看到,两者之间有几分钟的差异。

如果您想特别将范围限制为仅电子表格的更改,则将使用修订报告最准确的值。

function test() {
  const fileId = FILE_ID;
  console.log(getLastRevision(fileId)); // 2021-01-12T15:32:43.175Z
  console.log(getLastUpdated(fileId)); // Tue Jan 12 2021 15:53:53 GMT+0000 (Greenwich Mean Time)
  console.log(getLastUpdatedAdvanced(fileId)); // 2021-01-12T15:53:53.941Z
}

function getLastRevision(fileId) {
  let response;
  do {
    response = Drive.Revisions.list(fileId, { maxResults: 1000 });
  } while (response.nextPageToken);
  return response.items[response.items.length - 1].modifiedDate;
}

function getLastUpdated(fileId) {
  return DriveApp.getFileById(fileId).getLastUpdated();
}

function getLastUpdatedAdvanced(fileId) {
  return Drive.Files.get(fileId).modifiedDate;
}

我不知道您可能希望电子表格有多少次修订,但使用 anextPageToken非常简单。但是,如果电子表格将有数千个修订,并且您要经常轮询,那么它可能不是最有效的方法。

我无法用 复制延迟DriveApp.getFileById(fileId).getLastUpdated(),但它并没有让我觉得不寻常。您可以尝试使用Advanced Drive 服务,就像您使用 Revisions 所做的那样,来获取modifiedDate. 我希望这会返回延迟值。正如您所指出的,这可能是您的最佳选择,因为您无需担心修订的数量,但请记住,它也反映了非电子表格的更新。


推荐阅读