MrGreggles
MrGreggles

Reputation: 6175

Format for Google People API searchContacts()?

I'm making the transition from Contacts API to People API as required by Google. I'm very surprised by the lack of examples online but I can now create, delete and modify/update (thanks to the reply by @Tanaike's reply to Omar F. here: Cannot update contactusgin People api using Google Apps Script) a contact, with delete and modify via iterating through People.People.Connections.List(), with its max of 100 results (from the Apps Script sample here: https://developers.google.com/people/quickstart/apps-script).

But I have about 12,000 contacts and need to use (I assume) People.People.searchContacts(). I haven't found any Apps Script examples and the documentation is all in Java, which I don't know how to translate to Apps Script:

...

// Send search request
SearchResponse response = peopleService.people().searchContacts()
    .setQuery("query")
    .setReadMask("names,emailAddresses")
    .execute();

or "Protocol" which is similarly not useful (for me - I've tried!):

...
// Send search request after several seconds
GET /v1/people:searchContacts?query=query&readMask=names,emailAddresses HTTP/1.1
Host: people.googleapis.com

My best guess to date using Google Drive Query Parameter style since the People API link from this page (https://developers.google.com/people/v1/query-parameters) doesn't seem to help:

let searchResp = People.People.searchContacts(
    "phoneNumbers contains 5632",
    { readMask: "names,phoneNumbers,addresses,emailAddresses" }
  );

let personBob = searchResp.results.find(p =>
    p.names[0].displayName.includes("Bob Q22222")
  );

So after spending an embarrassing amount of time getting to this point, I'm throwing in the towel and hoping someone can give an example of getting a searchResponse via People.People.searchContacts() to show what

  1. A search query looks like and
  2. What a readMask looks like.

I understand that the searchResponse.results is just an array of People and should be fine from there.

Thank you and I hope this wasn't too waffly (baffled non-programmer for our little husband & wife business). ~


Edit: Almost there

Modified from Rafi's reply, this works from a form-attached Appscript file, which is what I want but it's not retrieving all results, see further below):

function run() {
  let query = "Q12755";
  let found = People.People.searchContacts({
    "query": query,
    "readMask": "names,addresses,emailAddresses,phoneNumbers"
  });

  if (found.results) {
    for (i = 0; i < found.results.length; i++) {
      let thisResult = found.results[i];
      Logger.log(`Result ${i}: ${thisResult.person.names[0].displayName}`);
    }
  } else {
    Logger.log(`No results for ${query}`);
  }
}

...but, it's not picking up all of the results.

The test function and result for "Q12755" query: The test function and result for "Q12755" query

Two results for that string in Google Contacts: Two results for that string in Google Contacts

And the same two results on my phone: And the same two results on my phone

Any idea why not all results are being retrieved? I've tested several queries and it consistently misses results. All (I believe) of the Contacts tested have been created via an Appscript script via the deprecating Contacts API.

P.S. I might add that it's not an issue with it only retrieving one result. In other cases where there "should" be like 20 results, in has retrieved half a dozen or so.

P.P.S. A "warmup" of the cache is recommended/required, and I'm assuming the updated script below does that okay. There's no difference to the results:

function run() {
  let blankQueryForWarmUp = "";
  let found = People.People.searchContacts({
    "query": blankQueryForWarmUp,
    "readMask": "names,addresses,emailAddresses,phoneNumbers"
  });

  Utilities.sleep(5000);

  let query = "Q12755";
  found = People.People.searchContacts({
    "query": query,
    "readMask": "names,addresses,emailAddresses,phoneNumbers"
  });

  if (found.results) {
    for (i = 0; i < found.results.length; i++) {
      let thisResult = found.results[i];
      Logger.log(`Result ${i}: ${thisResult.person.names[0].displayName}`);
    }
  } else {
    Logger.log(`No results for ${query}`);
  }
}

enter image description here

Upvotes: 1

Views: 1765

Answers (4)

HotDogWater
HotDogWater

Reputation: 113

I ran into a similar issue, and it turned out the the problem was that they contacts I was expecting to show up in the results are actually in the "Other contacts" group that Google creates for "people you've interacted with in Google products, as well as any contacts you've hidden from your list."

It doesn't look from you screenshots as though this is the problem you're having, although it's possible that Google's UI has changed since this was originally posted in a way that makes the issue more visible.

The Other Contacts group can be searched exactly the same way as the primary contacts group. Here is the code I ended up with, a function that looks up a person's name based on an email address (and returns the email address if nothing is found):

function getNameFromEmail_(email) {
      var name = email;
      var response;
    
      People.People.searchContacts({ //Warm up the cache
        query: '',
        readMask: 'names,emailAddresses',
      });
    
      response = People.People.searchContacts({
        query: email,
        readMask: 'names,emailAddresses'
      });
    
      // Check if the response contains contacts
      if (response.results && response.results.length > 0) {
        name = response.results[0].person.names[0].displayName;
      } else {
        People.OtherContacts.search({ //Warm up the cache
          query: '',
          readMask: 'names,emailAddresses',
        });
    
        response = People.OtherContacts.search({
          query: email,
          readMask: 'names,emailAddresses'
        });
    
        // Check if the response contains contacts
        if (response.results && response.results.length > 0) {
          name = response.results[0].person.names[0].displayName;
        }
      }
    
      return name;
    }

Upvotes: 0

Oz Ben-David
Oz Ben-David

Reputation: 1657

The reason you are not seeing all the results is that the search is being done on some google cache, and so, for refreshing it, according to the documentation at: https://developers.google.com/people/api/rest/v1/people/searchContacts

You must first send a "warmup" request, wait for a couple of seconds, and after that, send your request, yes, it is strange I know, but that is what the documentation says...

IMPORTANT: Before searching, clients should send a warmup request with an empty query to update the cache. See https://developers.google.com/people/v1/contacts#search_the_users_contacts

You can also see here how exactly it is being done (see the Java tab): https://developers.google.com/people/v1/contacts#search_the_users_contacts

CORRECTION: If you are searching by phone number, just know there is a bug on Google API See this thread - searchContacts with phone number query is broken Google say the bug was fixed and verified, but it wasn't at least while I'm writing this correction.

WORKAROUND: I just put the phone number also as one of the nickname field and so the search is working since this is one of the fields being searched at

Upvotes: 1

Wicket
Wicket

Reputation: 38160

Add pageSize property to the searchContacts parameter. The following example uses another resource but shows the use of pageSize (it's the same for many Google API's

function run() {
  var response;
  var options = {
    pageSize:10,
    personFields: 'names'
  };
  var callback = People.People.Connections.list
  do{
    response = callback('people/me',options)
  response.connections.forEach(connection => console.log(connection.names ? connection.names[0].displayName : ''));
  options.pageToken = response.nextPageToken
  } while(options.pageToken)
}

Related

Upvotes: 2

Rafa Guillermo
Rafa Guillermo

Reputation: 15357

Answer:

People API search queries only support partial string matches in contact names. The readMask values must be concatenated as a comma-separated string.

More Information:

People API Search Queries do not support the Drive syntax such as 'contains' keywords. From the documentation (emphasis my own):

query The plain-text query for the request. The query is used to match prefix phrases of the fields on a person. For example, a person with name "foo name" matches queries such as "f", "fo", "foo", "foo n", "nam", etc., but not "oo n".

The readMask can take any of the following values (taken from here), separated by commas:

  • addresses
  • ageRanges
  • biographies
  • birthdays
  • calendarUrls
  • clientData
  • coverPhotos
  • emailAddresses
  • events
  • externalIds
  • genders
  • imClients
  • interests
  • locales
  • locations
  • memberships
  • metadata
  • miscKeywords
  • names
  • nicknames
  • occupations
  • organizations
  • phoneNumbers
  • photos
  • relations
  • sipAddresses
  • skills
  • urls
  • userDefined

Code Example:

A full JavaScript request example would look like:

function run() {
  return gapi.client.people.people.searchContacts({
    "query": "Rafa Guillermo",
    "readMask": "names,emailAddresses,phoneNumbers"
  }).then(function(response) {
    console.log("Response", response)
  }, function(err) { 
    console.error(err);
  })
}

Upvotes: 1

Related Questions