I am trying to do a batch update that enters geocoordinates for 2000 records of a cuctom object called Property__c without gecoordinates using the following code:
Batch
global class batchUpdateAccountGeoLocation implements Database.Batchable<sObject>,Database.AllowsCallouts{
//Start
global Database.QueryLocator start(Database.BatchableContext BC){
string query = 'SELECT Id, Name, Property_Address__c,City__c,State__c,GeoCoord__Latitude__s,GeoCoord__Longitude__s FROM Property__c WHERE Property_Address__c!=null AND GeoCoord__Longitude__s = null';
system.debug('query::'+query);
return Database.getQueryLocator(query);
}
//Execute
global void execute(Database.BatchableContext BC,List<Property__c> scope){
for(Property__c a : scope){
GeoCodeResponse ogc = GeoCodeAddress.getGeoCodeAddress(a.Property_Address__c.replace(' ','+') + ',' + a.City__c + ',' + a.State__c);
if(ogc.status!='ZERO_RESULTS')
{
a.GeoCoord__Latitude__s = ogc.results[0].geometry.location.lat;
a.GeoCoord__Longitude__s = ogc.results[0].geometry.location.lng;
}
}
try{
system.debug('scope::'+scope);
update scope;
}catch(exception e){
system.debug('batchUpdateAccountGeoLocation exception:' + e.getMessage());
}
}
//Finish
global void finish(Database.BatchableContext BC){
}
}
Related Class
public class GeoCodeAddress {
public static GeoCodeResponse getGeoCodeAddress(String Address) {
string url ='https://maps.googleapis.com/maps/api/geocode/json?key=AIzaSyAa-MPRtAoFmdqnSJJIjRvZ7_lcKwwt8oI&address=' + EncodingUtil.urlEncode(Address, 'UTF-8');
// Instantiate a new http object
Http h = new Http();
// Instantiate a new HTTP request, specify the method (GET) as well as the endpoint
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod('GET');
// Send the request, and return a response
HttpResponse res = h.send(req);
system.debug('res::'+res.getBody());
return GeoCodeResponse.parse(res.getBody());
}
}
public class GeoCodeResponse {
public class Address_components {
public String long_name;
public String short_name;
public List<String> types;
}
public List<Results> results;
public String status;
public class Location {
public Double lat;
public Double lng;
}
public class Geometry {
public Location location;
public String location_type;
public Viewport viewport;
}
public class Results {
public List<Address_components> address_components;
public String formatted_address;
public Geometry geometry;
public List<String> types;
}
public class Viewport {
public Location northeast;
public Location southwest;
}
public static GeoCodeResponse parse(String json) {
return (GeoCodeResponse) System.JSON.deserialize(json, GeoCodeResponse.class);
}
}
However, when I run this, I get FATAL_ERROR|System.LimitException: Too many callouts: 101
I know that best practices is to use lists to do these sort of updates, and not execute them in a for loop, but I thought I was already doing that? My for loop does not update anything or make any soql calls. I also do not have any triggers on my Property object.
This is my first time using this sort of batch update so I hope that this is a simple error on my part. I see there are many similar questions, but I was not able to find a straight answer to my problem in any of them. Hopefully I do not get downvoted for this.
EDIT I changed my execute anonymous statement from
batchUpdateAccountGeoLocation c = new batchUpdateAccountGeoLocation();
Database.executeBatch(c,2000);
to
batchUpdateAccountGeoLocation c = new batchUpdateAccountGeoLocation();
Database.executeBatch(c,100);
Thinking that next I would attempt to update my records in several 100-record chunks and perhaps this would work. To my surprise, it seems to have updated all 2000 of my records. Not sure why this happened, but all my records now have geocoords.
GeoCodeAddress.getGeoCodeAddress
perform a query?Property__c
trigger(s). Looks like it can handle 100 but not 2000. If it's one query in a loop, it will fail on 101. Otherwise the problem might be more nuanced. You should share/investigate that trigger.