Reputation: 361
Is it possible to use Geocoder for retrieving, say, nearby users within a certain radius, and make it return the result of the distance calculation without having to repeat for display?
For example, say we use this (in a Rails application):
User.near(@me, 10, units: :km)
It will return an ActiveRecord::Relation
with all the users that are within 10 kilometres of user @me
.
If I now want to display a list with all the returned users and their distance to @me
, do I need to actually recompute the distances one by one using distance_to
, or is there are a way to make Geocoder
return the computed distances in an added model attribute (for example)?
Upvotes: 2
Views: 869
Reputation: 3057
I'm using this embedded Ruby version of the logic, which is similar logically to the answer given by @maxcal above. I'm including it because the trace below relates to this code.
<% for location in @location.nearbys(20) %>
<li> <span class="badge"><%= location.distance.round(2) %> miles</span> from here you'll find <strong>
<%= link_to location.name, location %> </strong> at <%= location.full_address %>.</li>
<% end %>
But, I think the answer is that Geocoder is creating a temp data store for the set of conforming records. .distance is the key variable.
If I look at the trace, it shows the initial database hits, but no subsequent hits for each item in the loop. One could look at the Geocoder code and confirm, but the trace seems to be conclusive.
[1m[36m (0.0ms)[0m [1mSELECT COUNT(*) FROM "reviews" WHERE "reviews"."user_id" = $1[0m [["user_id", 8]]
Rendered shared/_user_posted_badge.html.erb (15.6ms)
// Comment Geocoding starts here
Rendered locations/_map_show.html.erb (0.0ms)
[1m[35mLocation Load (0.0ms)[0m SELECT locations.*, 3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((30.267153 - locations.latitude) * PI() / 180 / 2), 2) + COS(30.267153 * PI() / 180) * COS(locations.latitude * PI() / 180) * POWER(SIN((-97.7430608 - locations.longitude) * PI() / 180 / 2), 2))) AS distance, MOD(CAST((ATAN2( ((locations.longitude - -97.7430608) / 57.2957795), ((locations.latitude - 30.267153) / 57.2957795)) * 57.2957795) + 360 AS decimal), 360) AS bearing FROM "locations" WHERE (locations.latitude BETWEEN 29.977689433778306 AND 30.556616566221695 AND locations.longitude BETWEEN -98.07821040202988 AND -97.40791119797011 AND (3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((30.267153 - locations.latitude) * PI() / 180 / 2), 2) + COS(30.267153 * PI() / 180) * COS(locations.latitude * PI() / 180) * POWER(SIN((-97.7430608 - locations.longitude) * PI() / 180 / 2), 2)))) BETWEEN 0.0 AND 20 AND locations.id != 65) ORDER BY distance ASC
// Geocoding section complete
[1m[36mPhotograph Exists (0.0ms)[0m [1mSELECT 1 AS one FROM "photographs" WHERE "photographs"."location_id" = $1 LIMIT 1[0m [["location_id", 65]]
[1m[35mPhotograph Load (0.0ms)[0m SELECT "photographs".* FROM "photographs" WHERE "photographs"."location_id" = $1 ORDER BY "photographs"."created_at" DESC [["location_id", 65]]
Upvotes: 1
Reputation: 101811
When you run a location-aware query the returned objects have two attributes added to them:
- obj.distance - number of miles from the search point to this object
- obj.bearing - direction from the search point to this object http://www.rubydoc.info/gems/rails-geocoder/0.9.11/frames#Distance_and_Bearing
User.near(@me, 10, units: :km).each do |user|
puts "#{user.name} is #{user.distance} clicks to the #{user.bearing}"
end
Upvotes: 1