I’m using DataMapper to manage a database that has points of interest (POIs) located by latitude and longitude. I would like to do a query and find all POIs within x distance of a given latitude and longitude. For example, all POIs within 1000m of latitude 45, longitude 90.
I set this up:
class POI
include DataMapper::Resource
property :id, String, :key => true
property :title, String, :required => true
property :lat, Float, :required => true
property :lon, Float, :required => true
def distance(latitude, longitude)
# Taken from https://github.com/almartin/Ruby-Haversine
earthRadius = 6371 # Earth's radius in km
# convert degrees to radians
def convDegRad(value)
unless value.nil? or value == 0
value = (value/180) * Math::PI
end
return value
end
deltaLat = (self.lat - latitude)
deltaLon = (self.lon - longitude)
deltaLat = convDegRad(deltaLat)
deltaLon = convDegRad(deltaLon)
# Calculate square of half the chord length between latitude and longitude
a = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) +
Math.cos((self.lat/180 * Math::PI)) * Math.cos((latitude/180 * Math::PI)) *
Math.sin(deltaLon/2) * Math.sin(deltaLon/2);
# Calculate the angular distance in radians
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
distance = earthRadius * c
return distance
end
end
I’d like to be able to find records with a call similar to this:
pois = POI.all(distance(45,90).lte => 1000)
But that gives an error:
./poi-provider.rb:44:in `<main>': undefined method `distance' for main:Object (NoMethodError)
I read dkubb’s answer about defining complex queries in a method but this is different because I need to pass parameters in and I’m trying to use the method as a condition.
How can I do that—or, is there a better way to use DataMapper to find points near a given latitude and longitude without breaking down and just using raw SQL?
Something like:
Then call