Is there a way to speed up/batch Google Calendar read/writes?

走远了吗. 提交于 2020-08-05 07:36:10

问题


I am new to Google Apps Script and learning javascript as I go about this project. Over the course of the introductory codelabs I noted the best practice to read all the data into an array with one command, perform operations, and then write it with one command.

I understood how to do this working with Google Sheets but how do I achieve this working with Google Calendar? I have come across a few links discussing batching with Google Calendar API and Advanced Google Services but I didn't understand how to make use of the information.

I basically hope to batch edit events instead of accessing Google Calendar repeatedly in a for loop.

function deleteMonth() {

  //  Set Date range to delete 
  var today = new Date();
  var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
  var lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);

  //  read spreadsheet data and get User Info from ss
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var idSheet = spreadsheet.getSheetByName('User Info');
  //Get users from sheet in array of objects with properties from column header in 
  //'User Info' (name, email, year, calName, calID, early, late)
  var userInfo = getSheetData(idSheet);
  var deletedNames = "";
  for (i = 0; i < userInfo.length; i++) {
    var calID = userInfo[i].calID;
    //    if we have calID proceed to delete events
    if (calID) {
      console.time("get events");
      var calendar = CalendarApp.getCalendarById(calID);
      var events = calendar.getEvents(firstDay, lastDay);
      console.timeEnd("get events");
      //    Delete events and add deleted name to string 
      //    deletedNames     
      for (i = 0; i < events.length; i++) {
        console.time("delete event");
        deletedNames += events[i].getTitle() + ", ";
        events[i].deleteEvent();
        console.timeEnd("delete event");
      }
    }
  }
  spreadsheet.toast("Deleted events: \n" + deletedNames);
}

Time output from console.time():

Other related links which sounded relevant:

  1. Using advanced google services (apps script resource)
  2. Google Developer blog?

回答1:


I believe your goal as follows

  • You want to delete all events in a month for several calendars using the batch process with Google Apps Script.
  • You want to reduce the process cost of above process.

For this, how about this answer?

Issue and workaround:

Calendar API can process with the batch requests. The batch requests can run 100 requests by one API call and can process with the asynchronous process. By this, I think that the process cost can bereduced. But, in the current stage, unfortunately, several calendar IDs cannot be used in one batch. When the requests including several calendar IDs, an error of Cannot perform operations on different calendars in the same batch request. occurs. So in your case, all events in a month in one calendar ID can be deleted in one batch requests. It is required to request the number of calendar IDs. I would like to propose this as the current workaround.

By the way, as the modification point of your scrit, in your script, the variable i is used in 1st for loop and 2nd for loop. By this, all values of userInfo are not used. Please be careful this.

Sample script:

Before you run the script, please enable Calendar API at Advanced Google services.

function deleteMonth() {
  var today = new Date();
  var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
  var lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var idSheet = spreadsheet.getSheetByName('User Info');
  var userInfo = getSheetData(idSheet);
  var deletedNames = "";
  var requests = []; // For batch requests.
  for (i = 0; i < userInfo.length; i++) {
    var req = [];
    var calID = userInfo[i].calID;
    if (calID) {
      var calendar = CalendarApp.getCalendarById(calID);
      var events = calendar.getEvents(firstDay, lastDay);
      for (j = 0; j < events.length; j++) {
        deletedNames += events[j].getTitle() + ", ";
        var e = events[j];
        req.push({
          method: "DELETE",
          endpoint: `https://www.googleapis.com/calendar/v3/calendars/${calID}/events/${e.getId().replace("@google.com", "")}`,
        });
      }
    }
    requests.push(req);
  }

  // Run batch requests.
  requests.forEach(req => {
    const limit = 100;
    const split = Math.ceil(req.length / limit);
    const boundary = "xxxxxxxxxx";
    for (let i = 0; i < split; i++) {
      const object = {batchPath: "batch/calendar/v3", requests: req.splice(0, limit)};
      const payload = object.requests.reduce((s, e, i) => s += "Content-Type: application/http\r\nContent-ID: " + i + "\r\n\r\n" + e.method + " " + e.endpoint + "\r\nContent-Type: application/json; charset=utf-8\r\n\r\n" + JSON.stringify(e.requestBody) + "\r\n--" + boundary + "\r\n", "--" + boundary + "\r\n");
      const params = {method: "post", contentType: "multipart/mixed; boundary=" + boundary, payload: payload, headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}, muteHttpExceptions: true};
      var res = UrlFetchApp.fetch("https://www.googleapis.com/" + object.batchPath, params);
      console.log(res.getContentText())
    }
  })

  spreadsheet.toast("Deleted events: \n" + deletedNames);
}

Note:

  • Please use this script with V8.

References:

  • Advanced Google services
  • Sending Batch Requests
  • Events: delete


来源:https://stackoverflow.com/questions/62205086/is-there-a-way-to-speed-up-batch-google-calendar-read-writes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!