rails Geocoder gem order by location from me - ruby-on-rails

I have Place model with lat and long fields.
So i need to select all places and order them using my geoposition.
I think that i need to use Geocoder gem.
So user send to me his lat & long
and i need to do smth like
Place.where(status: 1).and order them using my lat long.
How can i do?
Thanks

You would use the near method:
Place.where(status: 1).near( "Party City, Utah", 20 ) # Finds places within 20 miles
This will grab all Place records that are within a specific radius of the given location. In this case, your location is "Party City, Utah". You can add additional arguments to the near method to limit the number of results, and also edit the radius of your query.
More information in the GeoCoder Docs

Related

Geocoder search only by city?

I'm using Geocoder with google places API on my Ruby on Rails api,
I would like to search locations but only if the city params match my query string.
Eg. Searching for 'X' locations return cities called 'X', with no chance of returning a street or country also called 'X'.
Geocoder.search.city('X') #I'm aware that this doesn't work

Find nearest cafe and airports of a given latitude rails

I have latitude and longitude of an address and I want to search all the airports, Railway stations, Bus Stand and cafe etc popular places. I'm using these gems in my application :
gem 'geocoder'
gem 'gmaps4rails'
gem 'geokit-rails
Now Please suggest me how can I solve this problem?
We can pass the search parameters in type (these search strings are suggested by google for places)
lat="30.987674"
lng="-45.098753"
doc = JSON.parse(open("https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=#{lat},#{lng}&radius=50&type=['cafe']&name=cruise&key=xxxxxx").read)
cords=[]
doc['results'].each do |r|
tmp={}
tmp = r['geometry']['location']
tmp["name"] = r['name']
cords<< r['geometry']['location']
end
Here cords is the array of hashes with relative information about places i.e. cafes.
See : https://developers.google.com/places/web-service/search
https://developers.google.com/places/supported_types
I would actually use the near function of geocoder, assuming you use ActiveRecord.

How to get areas/regions for a country and cities for this area/region?

We made a simple query which gets some cities:
SELECT * FROM `allCountries` WHERE name='Moscow' and `country_code` = 'RU'
Here is the result of this query:
For example, for another city we get a result with 4-7 rows.
How to get all areas/regions for a country and then get all cities for this area/region?
P.S.: Please be careful. We are not interested in an API site and database fetch. Thanks!
Background
In Geonames you have feature_classes and feature_codes which discriminate the location type. You can find detailed description of the code in the Geonames website. As in your snapshot, P.PPLC means "City (populated place) which is capital of a political entity" and S.HLC means "building (spot) hotel".
Also, every geoname have properties to identify the location in the "hierarchy" inside a country; this properties are country_code, admin1_code, admin2_code, admin3_code, admin4_code. Note that not all properties are used for every given geoname, since this depends on the political organization of a country.
Find all city inside an administrative level
To find all city inside an area (i.e. administrative level), you must first search the geoname for that admin level, in order to have the admin codes useful to filter the city query.
To find an admin level, you must first execute a query like:
SELECT *
FROM `allCountries`
WHERE `country_code` = 'RU'
AND `feature_class`='A'
AND `feature_code`='ADM1'
Note that the query filter out only the first admin levels (feature_code='ADM1'), but you can find admin level of any depth by changing it to:
SELECT *
FROM `geonames`
WHERE `country_code` = 'RU'
AND `feature_class`='A'
AND `feature_code` LIKE 'ADM_'
Now, select one record from this result set and you it to search for the cities, by using the "hierarchy" codes of that level. You should use something like (mutatis mutandis):
SELECT *
FROM `geonames`
WHERE `country_code` = "RU"
AND `feature_class`='P'
AND `feature_code` LIKE 'PPL%'
AND `admin1_code`="<admin1>"
AND `admin2_code`="<admin2>"
AND `admin3_code`="<admin3>"
AND `admin4_code`="<admin4>"
Beware of NULL admin codes, which you need to strip out from the SQL (the whole "AND ..." clause).
Of course, you can do the original "Moscow" search inside this filtered set.
The answer for your question is pretty long, but this code snippet may help you a little bit. These queries obtain all hierarchy information about given geonameid (it's plpython inside postgres).
get_geoname = plpy.prepare("SELECT geonameid, asciiname, country, admin1, admin2 FROM all_countries where geonameid=$1",
["integer"])
get_country_name = plpy.prepare("SELECT name as country from country_info where code = upper($1)", ["varchar"])
get_admin1 = plpy.prepare("SELECT asciiname, name FROM admin1 where code = $1", ["text"])
get_admin2 = plpy.prepare("SELECT asciiname, name FROM admin2 where code = $1", ["text"])

finding locations within a particular distance using db2

I am using html5 geolocation api to get my position in latitude and longitude. I want to store them in a table of locations and want to retrieve those locations within a particular distance.
my current latitudes and longitudes are stored in variables "latval", "longval", "distance"
My table is "location"
columns are "location", "lat", "long"
I am using DB2 Express C as database and latitude and longitude columns are set as double type now. What type should I use to store these values and what would be the query to get location names within a distance
Thank you.
It looks like there's an extension for Express C that includes Spatial processing. I've never used it (and can't seem to get access at the moment), so I can't speak to it. I'm assuming that you'd want to use that (find all locations within a radius is a pretty standard query).
If for some reason you can't use the extension, here's what I would do:
Keep your table as-is, or maybe use a float data-type, although please use full attribute names (there's no reason to truncate them). For simple needs, the name of the 'location' can be stored in the table, but you may want to give it a numeric id if more than one thing is at the same location (so actual points are only in there once).
You're also going to want indicies covering latitude and longitude (probably one each way, or one covering each column).
Then, given a starting position and distance, use this query:
SELECT name, latitude, longitude
FROM location
WHERE (latitude >= :currentLatitude - :distance
AND latitude <= :currentLatitude + :distance)
AND (longitude >= :currentLongitude - :distance
AND longitude <= :currentLongitude + :distance)
-- The previous four lines reduce the points selected to a box.
-- This is, or course, not completely correct, but should allow
-- the query to use the indicies to greatly reduce the initial
-- set of points evaluated.
-- You may wish to flip the condition and use ABS(), but
-- I don't think that would use the index...
AND POWER(latitude - :currentLatitude, 2) + POWER(longitude - :currentLongitude, 2)
<= POWER (:distance, 2)
-- This uses the pythagorean theorem to find all points within the specified
-- distance. This works best if the points have been pre-limited in some
-- way, because an index would almost certainly not be used otherwise.
-- Note that, on a spherical surface, this isn't completely accurate
-- - namely, distances between longitude points get shorter the farther
-- from the equator the latitude is -
-- but for your purposes is likely to be fine.
EDIT:
Found this after searching for 2 seconds on google, which also reminded me that :distance would be in the wrong units. The revised query is:
WITH Nearby (name, latitude, longitude, dist) as (
SELECT name, latitdude, longitude,
ACOS(SIN(RADIANS(latitude)) * SIN(RADIANS(:currentLatitude)) +
COS(RADIANS(latitude)) * COS(RADIANS(:currentLatitude)) *
COS(RADIANS(:currentLongitude - longitude))) * :RADIUS_OF_EARTH as dist
FROM location
WHERE (latitude >= :currentLatitude - DEGREES(:distance / :RADIUS_OF_EARTH)
AND latitude <= :currentLatitude + DEGREES(:distance / :RADIUS_OF_EARTH))
AND (longitude >= :currentLongitude -
DEGREES(:distance / :RADIUS_OF_EARTH / COS(RADIANS(:currentLatitude)))
AND longitude <= :currentLongitude +
DEGREES(:distance / :RADIUS_OF_EARTH / COS(RADIANS(:currentLatitude))))
)
SELECT *
FROM Nearby
WHERE dist <= :distance
Please note that wrapping the distance function in a UDF marked DETERMINISTIC would allow it to be placed in both the SELECT and HAVING portions, but only actually be called once, eliminating the need for the CTE.

Detecting Possible Duplicates in Rails

I have a Rails 3 application that has a model w/ a Name, and a Geographic Location (lat/lng). How would I go about search for possible duplicates in my model. I want to create a cron job or something that checks to see if two objects have a similar name and that they are less than 0.5 miles away from each other. If this matches then we'll flag the objects or something.
I am using Ruby Geocoder and ThinkingSphinx in my application.
Levenshtein is as good a way as any for judging the similarity of two text strings, ie the names.
What i would suggest is to (as well as, or instead of, the single "lat;long" string) store the latitude and longitude seperately. Then you can do an sql query to find other records that are within a certain distance, THEN run the levenshtein on their names. You want to try to run the lev as few times as possible as it's slow.
Then you could do something like this: let's say your model name is "Place":
class Place < ActiveRecord::Base
def nearby_places
range = 0.005; #adjust this to get the proximity you want
#lat and long are fields to hold the latitude and longitude as floats
Place.find(:all, :conditions => ["id <> ? and lat > ? and lat < ? and long > ? and long < ?", self.id, self.lat - range, self.lat + range, self.long - range, self.long + range])
end
def similars
self.nearby_places.select do |place|
#levenshtein logic here - return true if self.name and place.name are similar according to your criteria
end
end
end
I've set range to 0.005 but i've no idea what it should be for 1/2 a mile. Let's work it out: google says one degree of latitude is 69.13 miles, so i guess half a mile in degrees would be 1/(69.13 * 2) which gives 0.0072, so not a bad guess :)
Note that my search logic would return places that are anywhere within a square which is a mile per side, with our current place in the centre. This would potentially include more places than a circle with 1/2 mile radius with our current place in the centre, but it's probably fine as a quick way of getting some nearby places.

Resources