From 734013cd1a11be4e6f4fbf344e1fb94d93cdfb6f Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 15:05:03 +0000 Subject: [PATCH] Convert from MongoDB geolocation finder to raw SQL query --- app/models/post.rb | 52 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index 73fe0d4..dd62fc6 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1,13 +1,51 @@ class Post < ActiveRecord::Base belongs_to :feed - EARTH_RADIUS_M = 6378000 + EARTH_RADIUS_METRES = 6378000 - def self.near(lat, lng, radius_m) - all( - :loc => { - '$nearSphere' => [ lng, lat ], - '$maxDistance' => radius_m / EARTH_RADIUS_M - }) + def self.near(lat, lon, radius_metres) + # Santize inputs. Is this necessary? + lat = lat.to_f + lon = lon.to_f + radius_metres = radius_metres.to_i + + # Calculate distance using the Haversine formula + self.find_by_sql(<<-ENDQUERY + SELECT + p.id, + p.title, + p.summary, + p.url, + p.lat, + p.lon, + p.published, + f.title as feed_title, + ( #{EARTH_RADIUS_METRES} + * acos( cos( radians('#{lat}') ) + * cos( radians( p.lat ) ) + * cos( radians( p.lon ) + - radians('#{lon}') ) + + sin( radians('#{lat}') ) + * sin( radians( p.lat ) ) ) ) + As distance + + FROM posts p + INNER JOIN feeds f + ON p.feed_id = f.id + + WHERE + ( #{EARTH_RADIUS_METRES} + * acos( cos( radians('#{lat}') ) + * cos( radians( p.lat ) ) + * cos( radians( p.lon ) + - radians('#{lon}') ) + + sin( radians('#{lat}') ) + * sin( radians( p.lat ) ) ) ) + < #{radius_metres} + + ORDER BY distance + + ENDQUERY + ) end end