domi91c
domi91c

Reputation: 2053

Geocoding nearby locations uses too many Google Maps queries

I'm using this code to get all ads on my site which are within a given distance. I have two models, Ad and Location. Every Ad has_one Location. I am geocoding the address field of every Location to find those which are within range of a user's search.

This code probably needs refactoring, but I managed to get it to do what I need it to; when a user searches an address, all ads within a certain distance are displayed.

The problem is that the code performs a query on every ad, and with 1000 ads in my database, this quickly goes over Google Maps' limit. I have buttons which the user can click to change the distance to search, and each click again performs a query on every ad. Is there another way I can code this which will not require so many queries?

    #find ads with locations in range of user address search
    ads_within_distance = Ad.select { |ad| ad.location.distance_from(cookies[:search_address]) <= distance.to_f }

    ads_within_distance.each do |ad|
        nearby_ads_id_array = ad.id
    end

    @nearby_ads = Ads.where(id: nearby_ads_id_array).paginate(:page => params[:page], :per_page => 5).order('created_at DESC')

This can obviously be done, as many sites such as meetup.com have this feature. I'm willing to use whatever method is most efficient. I'd really appreciate any input.

Upvotes: 0

Views: 331

Answers (1)

saskcan
saskcan

Reputation: 178

There are two problems with your approach. I am assuming that a location can have many ads. If this is the case, your associations should be:

class Location < ActiveRecord::Base
  has_many :ads
  ...
end

class Ad < ActiveRecord::Base
  belongs_to :location
  ...
end

Since you are iterating over ads, you are potentially checking distances many times for the same location.

Secondly, since you are passing in an address, you are geocoding for each ad even though you only have a single address which you don't have a lat and long for (the user-entered address). I am assuming that your locations in the database have already been geocoded and you have a lat and long for each.

If you are using the geocoder gem (https://github.com/alexreisner/geocoder), you can write:

nearby_locations = Location.near(cookies[:search_address], distance.to_f)

Then you can find all the ads which belong to those locations by:

nearby_ads = Ad.where(location_id: nearby_locations)

Good luck.

Upvotes: 2

Related Questions