For the Electoral API extension, I want to write a scheduled job to look up legislative data for everyone who a) has a geocode, and b) doesn't already have legislative data (which is stored in a multi-record custom field). I need this to be scalable.

So I could look up every contact without legislative data, then check those contacts for geocodes, or vice versa. Either way, I'm checking a huge number of contacts for data. Is there a better way? Maybe using API chaining?

Is it possible to create a smart group that's hidden from the UI that meets these criteria, then use that as the basis for my scheduled job? That seems like the best option.

  • A key requirement of scalability is to have proper indexes. Make sure you have an index on civicrm_address.geo_code_1, and on the contact ID field of the custom table as well. If it's still too slow once indexes are in place, it may require skipping the API and writing the optimized SQL directly. If you get to that point, I'm happy to review the query and make optimization suggestions.
    – Nicholai
    Aug 13, 2015 at 2:34

1 Answer 1


I don't know the answer about hidden smart groups but I took a swipe at the API chaining and was able to pull a contact on the demo server that met one criteria on the contact and another on the geocode on the address:

API Explorer

I don't know if that is helpful at all, but if you can get the first portion of this API call working with your custom field, it seems you should be able to chain the geocode to it.

The code for the above comes out like this (PHP):

$result = civicrm_api3('Contact', 'get', array(
'sequential' => 1,
'custom_11' => 1,
'api.Address.get' => "array( 'geo_code_1' => array('IS NOT NULL' => 1), )",

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.