Home > Blockchain >  ContactsApp.getContacts() from Google Apps Script does not behave as expected
ContactsApp.getContacts() from Google Apps Script does not behave as expected

Time:12-31

I have a script to get all contacts from Google Contacts to a spreadsheet in Google Sheets. Because the amount of contacts is too many to get in 6 minutes execution time limit, I use script trigger to continue the import after some time.

...
var contacts = ContactsApp.getContacts();
var last_index = parseInt(userProperties.getProperty('last_index'));
if(isNaN(last_index)) last_index = 0;
for(var i = last_index; i < contacts.length;   i){
  // register trigger if time is up
  // ....
  
  var name = contacts[i].getFullName();
  sheet.appendRow([name]);
}
...

What works:

  1. When time limit is hit (I set it to 4 minutes), trigger does run and continue the import.

What doesn't work:

  1. The execution chain will randomly stop at somepoint, resulting in incomplete import.
  2. Even if the contacts' size is small enough to be fetched in 4 minutes, the number of contacts imported sometimes doesn't match with contacts.length. Most of the time it will match.
  3. To compensate (1). I make a new menu to continue import from last index derived from total rows written in the sheet. BUT, when it's done this way the contacts imported will start from the first index no matter which index I asked the script to start from.

For example:

for(var i = last_row;i<contacts.length;  i){ // I've checked last_row is indeed not 0
  var name = contacts[i].getFullName();
  // append row
}

will yield the same result as:

for(var i = 0;i<contacts.length;  i){
  var name = contacts[i].getFullName();
  // append row
}

No matter what index I asked to start from, it will always start from the first index of contacts array unless it's executed from trigger chaining. Could anyone please tell me what's going on here? How do I fix this?

CodePudding user response:

In your script, appendRow is used in a loop. In this case, the process cost becomes high. Ref I guessed that this might be the reason for your process time. If my understanding of your issue was correct, how about the following modification?

From:

var contacts = ContactsApp.getContacts();
var last_index = parseInt(userProperties.getProperty('last_index'));
if(isNaN(last_index)) last_index = 0;
for(var i = last_index; i < contacts.length;   i){
  // register trigger if time is up
  // ....
  
  var name = contacts[i].getFullName();
  sheet.appendRow([name]);
}

To:

var contacts = ContactsApp.getContacts();
var values = contacts.map(e => [e.getFullName()]);
sheet.getRange(sheet.getLastRow()   1, 1, values.length).setValues(values);
  • In this modification, the values are put to an array, and the array is put to the Spreadsheet using setValues. By this, I thought that this process might be run by one execution.

Another approach:

As another approach, how about using People API? When People API is used, the sample script is as follows. If you use this script, please enable People API at Advanced Google services.

function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var values = [];
  var pageToken = "";
  do {
    var o1 = People.People.Connections.list("people/me", { personFields: "names", fields: "connections.names.displayName,nextPageToken", pageSize: 1000, pageToken });
    if (o1.connections.length > 0) {
      values.push(...o1.connections.map(e => e.names ? e.names.map(f => [f.displayName]) : [[""]]));
    }
    pageToken = o1.nextPageToken;
  } while (pageToken);
  do {
    var o2 = People.OtherContacts.list({ readMask: "names", fields: "otherContacts.names.displayName,nextPageToken", pageSize: 1000, pageToken });
    if (o2.otherContacts.length > 0) {
      values.push(...o2.otherContacts.flatMap(e => e.names ? e.names.map(f => [f.displayName]) : [[""]]));
    }
    pageToken = o2.nextPageToken;
  } while (pageToken);
  sheet.getRange(sheet.getLastRow()   1, 1, values.length).setValues(values);
}
  • In this sample, the values are put to the active sheet. Please modify this for your actual situation.

References:

  • Related