4

How can I perform a query on the database as per the user's location value? The application was developed with HTML5, CSS, Javascript, PHP has a database with columns as in the below table.

database structure

On the html webpage the users geo coordinates are collected and are to be compared with the values in the database to find the nearest place to the user with the places in the database.

Please let me know how to achieve this. Any examples / samples will be appreciated.

Community
  • 1
  • 1
user3916007
  • 189
  • 1
  • 9
  • mysql has a few geospatial functions, but is pretty badly limited in what it can do. PostGIS for postgres has simple functions to do what you are looking for here. Oracle and microsoft also have implementations of GIS as well. – Twelfth Aug 06 '14 at 21:08
  • Can you add any examples for each. There is a great blog for mysql geospatial features . [here](http://www.mysqlperformanceblog.com/2013/10/21/using-the-new-spatial-functions-in-mysql-5-6-for-geo-enabled-applications/) . I am trying to compare each database limitations and capabilities for the above scenario – user3916007 Aug 06 '14 at 21:37
  • MySQL is a bit late to the game and it's features here were added long after the others have. PostGIS is significantly superior (especially in the indexing conversation), especially if you are dealing with polygon's and not just points...PostGIS is a tag on stackoverflow, browse those for an idea of the problems that arise and the solutions that we come up with. From the link in your last comment : MySQL 5.6 supports st_distance functions with 2 drawbacks: 1.It only supports planar coordinates 2.It does not use index I think those limits are only in MySQL now... – Twelfth Aug 06 '14 at 21:46
  • Can't add Microsoft and Oracle example off hand, but I know ms is all about the geography data type (think of 3d, including an altitude to the usual 2-d lat/long polygon) and Oracle is quite advanced (took them 2 days to do a presentation to show how advanced they were). I do know MySQL in particular is hurting on this and hits scalability issues right away (under 10k lines and mySQL will start puking...from personal experience anyway. Using the b-tree postgis indexing in postgres, I was able to locate a few hundred million points with the correct polygon they fit into with a couple minutes) – Twelfth Aug 06 '14 at 21:55
  • @user3916007. If you are not interested in the Postgis approach, perhaps you could remove the tag from your question? – John Powell Aug 11 '14 at 14:54
  • Thanks John for your valuable suggestions. Though i am a MYSQL guy i am inclined considering POSTGIS for the product development. I am new to POSTGIS , so taking some time comparing it with other DBs. – user3916007 Aug 12 '14 at 00:07

2 Answers2

3

There is a question that compares the capabilities of various spatial databases, GIS: PostGIS/PostgreSQL vs. MySql vs. SQL Server?, where Postgis comes out a pretty clear winner over MySQL.

Whether you use MySQL or Postgis, you would be much better off, if you can, storing your latitude and longitude values as a geometry/geography (Point), as the functions that can be used to find things nearby, ST_Distance, ST_Distance_Sphere and the more obscure <-> operator, see Find n Nearest Neighbors for given Point using PostGIS? (for example usage) work directly on geometry/geography columns. Even more importantly, you can add a spatial index, which these functions need to work properly, which will outperform searches on separately indexed latitude and longitude columns by a large margin (this will depend on table size, but will grow as table size grows),

In Postgis, you can convert lat and lon to a geometry with:

alter table mytable add column geom (Geometry, 4326);
update mytable set geom = ST_SetSRID(ST_MakePoint(lon, lat), 4326)
create index ix_spatial_mytable_geom on mytable using gist(geom);

At this point, you will be able to very efficient queries to find points near other points, using any of the examples in the above links.

You can do similar things in MySQL, although, it does not support a spatial reference system, ie, the 4326 above, which means lat/lon, and it lacks a ST_MakePoint function, so you would need to use STGeomFromText and concatenate the lat/lon together to make a POINT. It also does everything in planar coordinates, as Claudio and others have stated, which is not an issue with Postgis.

I apologize for a long and somewhat tangential answer, but having done various migrations between databases on large amounts of data (MySQL, SQL Server and Postgres/GIS) and made lots of mistakes on the way, I hope I can set you off in the right direction (and add a bit of future proofing, if you want to start using some other spatial functionality, which Postigs has in spades).

Community
  • 1
  • 1
John Powell
  • 12,253
  • 6
  • 59
  • 67
2

For a rough measure I would try something like the following (only Euclidean geometry, it doesn't take into account the Earth curvature or problems like this).

First you could compute the difference between the user's coordinates and the coordinates of places in the database. Like this:

distLat = abs(userLat - placeLat)
distLong = abs(userLong - placeLong)

Then I would compute the distance between the two points using Pythagora's theorem. So:

distance = squareRoot(distLat * distLat + distLong * distLong)

You can compare the distances of all places in the database and take the minimum, which teoreticaly is the place nearest to the user's position.

If you use MySQL I think that a query like this should work:

SELECT * FROM places ORDER BY MIN(SQRT((p.latitude - userLatitude) * (p.latitude - userLatitude) + (p.longitude - userLongitude) * (p.longitude - userLongitude))) LIMIT 1

Beware that this query could be very slow depending on how many places you have, because it needs to read all the rows in the table and compute the distance for each one. Indexes have no effects.

Anyway, for this kind of problems you should better use GIS or databases with good geospatial extensions. MySQL geospatial extension is not very powerful, even in MySQL 5.6. It has a ST_DISTANCE function but still uses Euclidean geometry which is not very accurate for calculation on a spherical surface like the Earth. Anyway, if you use MySQL 5.6, I think that it should be better to use the ST_DISTANCE function, which is for sure much more optimized than doing calculations "manually" in the query.

See also this article for a deep explanation and more examples: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc

EDIT

As requested by the OP, I add more details on how to deal with negative coordinates.

Negative coordinates are generally not a big issue. I will try to explain this with some examples.

Take for example the coordinates of the Brooklyn bridge: 40.704391, -73.994675. With the above formula, the distance of the Brooklyn bridge from the Statue of Liberty is:

sqrt((40.704391 - 40.689167)^2 + (-73.994675 - -74.044444)^2) = 0.052045399

Now consider the distance between the Statue of Liberty and the Brooklyn Bowl (coordinates 40.7179666, -73.9670125), that is:

sqrt((40.7179666 - 40.689167)^2 + (-73.9670125 - -74.044444)^2) = 0.082613886

As you can see the distance of the Brooklyn Bowl from the Statue of Liberty is bigger than the distance of the Brooklyn Bridge. It is correct since the Brooklyn Bowl is 4 miles away from the Statue of Liberty, while the Brooklyn Bridge is only 1 mile away from it.

In this example both the two points has a negative longitude. But the formula works even if one of the two has positive coordinates. For example, the distance between the Statue of Liberty and the Tour Eiffel (Paris, coordinates 48.858360, 2.294460), is:

 sqrt((48.858360 - 40.689167)^2 + (2.294460 - -74.044444)^2) = 76.77476134

Then calculate also the distance between the Statue of Liberty and the Colosseum (Rome, coordinates 41.890238, 12.492242):

sqrt((41.890238 - 40.689167)^2 + (12.492242 - -74.044444)^2) = 86.54502063

As you can see it works, the distance of the Colosseum is bigger since it is about 8000km away from the Statue of Liberty, while the Tour Eiffel is about 800 km closer.

The only issue I see is when you have to calculate the distance between two places that are in the far east and in the far west respectively. The above formula will give you a very high distance, but actually the they could be very close. Take for example Anchorage, a city in Alaska (coordinates 61.252240, -149.896769), and Beringovskij, a city in the very east of Russia (coordinates 63.049797, 179.310011). They have a distance of only about 1500 km but with the above formula you get:

sqrt((61.252240 - 63.049797)^2 + (-149.896769 - 179.310011)^2) = 329.2116875

Definitely a too high value for only 1500 km: I would expect something less than 50.

The problem is that the formula calculates the distance taking the central meridian as a reference point, that is the meridian with a 0 degrees latitude. This is good until the distance is "no more that half the Earth".

I think that a solution could be to calculate two distances. The first with a reference point of 0 degrees: it is what the above formula does. The second with a reference point of 180 degrees. It's like calculating the distance on a world map shifted by 180 degrees, like this: http://www.bouwman.com/world/Formilab-180.html. And then take the minimum of these two distances.

Thus the formula becomes a little more complex:

distance = squareRoot(min((userLat - placeLat)^2, (userLat - placeLat - 360)^2) + (userLong - placeLong)^2)

Note that we subtract 360 because it is the distance between the degree -180 and the degree 180.

With this new formula we get correct results for places that are more then 180 degrees away from each other, and we get also the same result given by the previous formula when comparing places that are less then 180 degrees away from each other. The calculate distance Anchorage - Beringovskij is now: 30.84564166.

Of course, as I have already said, this is not an exact method for calculating distances. You can take a look at this article for more "scientific" techniques: https://en.wikipedia.org/wiki/Geographical_distance :D

  • Claudio, I am confused if the logic to find the difference between users latitude ,longitude with the values in database and find he distance would be valid . How do we deal with any negative values as of 'statue of liberty ' in the question. – user3916007 Aug 07 '14 at 18:34
  • Claudio, can you suggest how can the formula which includes negative values be written in MYSQL query. – user3916007 Aug 23 '14 at 10:36
  • SELECT * FROM geomduplicate ORDER BY MIN(SQRT((geomduplicate.latitude - 51.503363) * (geomduplicate.latitude - 0.1276250) + (geomduplicate.longitude - 0.1276250) * (geomduplicate.longitude - 0.1276250))) LIMIT 1 ---->i tried the above ormula but not working , throwing empty rows – user3916007 Aug 23 '14 at 15:55