Django: Filter on Annotated Value - mysql

I have a situation where I have a model called trip. Each trip has a departure_airport and an arrival_airport which are related fields and both part of the airport model. Each object in the airport model has a location represented by latitude and longitude fields.
I need to be able to take inputs from two (potentially) separate departure and arrival airport locations using something like the Haversine formula. That formula would calculate the distance from each departure/arrival airport in the database to the location of the airports that have been taken as input.
The difficult part of this query is that I annotate the trip queryset with the locations of the departure and arrival airports, however because there's two sets of latitude/longitude fields (one for each airport) with the same name and you can't use annotated fields in a sql where clause, I'm not able to use both sets of airports in a query.
I believe the solution is to use a subquery on the annotated fields so that query executes before the where clause, however I've been unable to determine if this is possible for this query. The other option is to write raw_sql.
Here's what I have so far:
GCD_FORMULA_TO = """3961 * acos(
cos(radians(%s)) * cos(radians(arrival_lat))
* cos(radians(arrival_lon) - radians(%s)) +
sin(radians(%s)) * sin(radians(arrival_lat)))"""
GCD_FORMULA_FROM = """3961 * acos(
cos(radians(%s)) * cos(radians(departure_lat))
* cos(radians(departure_lon) - radians(%s)) +
sin(radians(%s)) * sin(radians(departure_lat)))"""
location_to = Q(location_to__lt=self.arrival_airport_rad)
location_from = Q(location_from__lt=self.departure_airport_rad)
qs = self.queryset\
.annotate(arrival_lat=F('arrival_airport__latitude_deg'))\
.annotate(arrival_lon_to=F('arrival_airport__longitude_deg'))\
.annotate(departure_lat=F('departure_airport__latitude_deg'))\
.annotate(longitude_lon=F('departure_airport__longitude_deg'))\
.annotate(location_to=RawSQL(GCD_FORMULA_TO, (self.arrival_airport.latitude_deg, self.arrival_airport.longitude_deg,
self.arrival_airport.latitude_deg)))\
.annotate(location_from=RawSQL(self.GCD_FORMULA_FROM, (self.departure_airport.latitude_deg, self.departure_airport.longitude_deg,
self.departure_airport.latitude_deg)))\
.filter(location_to and location_from)
return qs
Any ideas? Also open to other ways to go about this.

You're doing this the hard way.
If your python code has a pair of locations, use this:
from geopy.distance import distance
loc1 = (lat1, lng1)
loc2 = (lat2, lng2)
d = distance(loc1, loc2).km
If you're querying a database, perhaps you would prefer that it runs PostGIS / Postgres, rather than mysql,
so you can compute distance and shape membership.
The syntax sometimes is on the clunky side, but the indexing works great.
Here is an example for departing from London Heathrow:
SELECT a.airport_name,
ST_Distance('SRID=4326; POINT(-0.461389 51.4775)'::geography,
ST_Point(a.longitude, a.latitude)) AS distance
FROM arrival_airports a
ORDER BY distance;
As a separate matter, you might consider defining an arrival and/or departure VIEW on your table, and then JOIN, with a distinct model for each view.

Related

Search a rectangle on googlemaps

We have Locations data in Sql server database. Four points (bounding rectangle) are defined for each Location. Four points are Bottom Latitude, Top Latitude, Left Longitude, Right Longitude. If googlemaps falls within any area of the bounding rectangle, a marker will be plotted for that location.
We have some other locations in the database for which we have stored only Lat Lng and we are searching them using below query and it works!
SELECT *
FROM SomeOtherLocationsTable
WHERE LocationLatitude >= #bottomlat AND
LocationLatitude <= #toplat AND
LocationLongitue >= #leftlang AND
LocationLongitue <= #rightlng
How we can search locations having four points defined for them?
Use STIntersects
Instead of Numbers you should store geometries (then you may use the same query for POINTS and POLYGONS)
After some R & D, we were able to find below solution and works for us (we need the functionality for USA locations only):
SELECT *
FROM LocationsTable
WHERE
NorthEastLongitudeRectangle < #SouthWestLongitudeRectangle OR
SouthWestLongitudeRectangle > #NorthEastLongitudeRectangle OR
NorthEastLatitudeRectangle < #SouthWestLatitudeRectangle OR
SouthWestLatitudeRectangle1 > #NorthEastLatitudeRectangle
We are still testing it, but hopefully it will work!

Google map display markers by hours and location

I am trying to implement a recovery community meeting finder. I have a database and map setup. I am trying to add a variable to display the current day's meetings that is also based upon a "nearest" location priority. How do I get the today's date variable in my database to selectively display only that days meetings? I'm using google maps api.
Thanks,
Terry
In your database you have a datetime field that you store the date and time of the meetings I am guessing.
When you pull the information from your database to put in the map, simply use whichever apprrpriate sql language to select only those records that match the date you need.
This is actually more of a sql problem.
The closest location may not be catered for, but what you need to do is also a sql question. You need to add lat and long fields to your database and store the lat/longs for each of the meeting locations.
Then you can do a distance based sql search once you have those and the lat/long of the user.
Maps doesn't come into the selection process at all.
...
Edit.
The selecting by time is fairly simple but I thought I would share a distance based sql SELECT I used a while back. Note. It was used with MySQL but I think it should work with almost any sql db.
"SELECT name, tel, (((acos(sin((".$latitude."*pi()/180)) * sin((`latitude`*pi()/180))+cos((".$latitude."*pi()/180)) * cos((`latitude`*pi()/180)) * cos(((".$longitude."- `longitude`)*pi()/180))))*180/pi())*60*1.1515) AS distance FROM takeaway WHERE active AND (((acos(sin((".$latitude."*pi()/180)) * sin((`latitude`*pi()/180))+cos((".$latitude."*pi()/180)) * cos((`latitude`*pi()/180)) * cos(((".$longitude."- `longitude`)*pi()/180))))*180/pi())*60*1.1515) < 10 AND tel AND type = 'transport/taxi' ORDER BY distance LIMIT 5"
That gives you the basics for editing and reusing. Just remember to add the time/date check into your final string.

Sql queries for getting information from GTFS files in Java

I'm working on a project for school which uses gtfs database (MySQL).
I wrote some code that parses the gtfs files and inserts them into MySQL DB (each file is a table in my DB).
I'm trying to write two SQL queries:
Given a stationId, time, and line number - I want to get all trips that pass by this station in the next 10 minutes.
Given a tripId, directionId and stopId - I want to get all the remaining stations in this trip (in order to draw on a map the stations to come in my trip).
Does anyone knows how can I state this SQL queries in Java?
I tried this:
SELECT * FROM stops, routes, stop_times, calendar, trips
where departure_time > "08:24:00"
and departure_time < "16:40:00"
and route_short_name = "10"
and stops.stop_id = 29335
and stops.stop_id = stop_times.stop_id
and stop_times.trip_id = trips.trip_id
and calendar.service_id = trips.service_id
and calendar.sunday = 1
I have fixed this problem exactly for GTFS data in Belgium. The code is available on github:
https://github.com/iRail/MIVBSTIBResource/blob/master/MIVBSTIBStopTimesDao.php

lat lng distances automated from fixed positions to lan lng in database ( australia )

Ok this is a big ask, I have been reading a lot about this on here and over the tinternet.
The best I have found is : this link
Now Here is our issue ( this is just for Australian distances )
We have a database of lat and lng values for every single suburb in Australia.
My question is ... is there a way we could run some kind of script pinging our servers, and storing the results in a large db.
So a bit like:
record a: lat lng -> record b: lat lng ( do calculation and store distance in record )
record a: lat lng -> record b: lat lng ( do calculation and store distance in record )
and so on ( and do not do record b: lat lng -> record a: lat lng ( as this is already known )
At the moment the easiest way of accessing this data is via real world names such as suburb state and postcode, which we have within the db along with the lat lng values.
Those are really superfluous as each data entry has an id. similar to my example above.
The objective is to get :
ID 1 -> ID2 distance =:75 km
Where ID1 = -27.4561899, 153.3564564 ( known name Raby Bay QLD 4163 )
and ID2 = -27.1054534, 152.948145 ( known name Morayfield QLD 4560 )
do you get where I am going with this...
So my question is does anyone know of a way we can run an automated script, that will grab the ID then the next ID record and perform a function and save the result to the db and then do the next ... so on and so forth.
We have extremely fast servers, and there are some 13000 individual records ( suburbs ) for us to pit against each other..
Which will give us approximately 84,506,500 results ( .ish )
obviously we would need to do calculations for the same ID because then we can echo 0 km
So any suggestions, has anyone seen or done anything like this before ??
Is there a better way, we would ideally like to do this server side ( and store results ) then spew them out on page load...
Because this is for members site and advertised items.. so we know:
Advertisers location and Vistiors location so would want to spew out the distance from buyer to seller on the fly. Without running large client side code.
Ste
The calculations are not really that difficult -- certainly not worth precomputing 84M+ rows in a table, where almost certainly very few of them will ever be used.
The only time I have ever needed to precompute a lot if data like this is to store a list of "closest locations" for each location in the database, and that can be done with a much smaller table. (and even that isn't always necessary, as you can sometimes get the same data with a bounding box query)
If you're set on this architecture, have you considered using the table as a cache, to store the results as people ask for them, and them having it be the first place that your application looks for an answer when a new query arrives?

MySQL self-join to get two geographically closest items with different properties?

We have a single table of weather markers on a map, where each marker type is either wind or cloud.
For each cloud marker we want to find the "WindDir" field value for the closest wind marker. It seems like a self-join would do the trick, but constructing the query is proving difficult.
Below is our incorrect pseudo SQL. We know the Distance value will be what we want. We just need to how to make the query find the closest wind marker for each cloud marker, so that we can get the wind marker's "WindDir" value.
SELECT w1.ID AS ID, w1.Lat AS Lat, w1.Lng AS Lng,
w2.WindDir AS WindDir,
MIN(SQRT(POWER(ABS(w1.Lng - w2.Lng), 2) + POWER(ABS(w1.Lat - w2.Lat), 2))*60) AS Distance
FROM Weather w1 WHERE w1.Marker="Cloud"
LEFT JOIN Weather w2 WHERE w2.Marker="Wind"
USING ID
We'd be grateful for any advice on making a version that works!
-Ken
You're pretty close (basically just reordered for syntax)
SELECT w1.ID AS ID, w1.Lat AS Lat, w1.Lng AS Lng,
w2.WindDir AS WindDir,
(SQRT(POWER(ABS(w1.Lng - w2.Lng), 2) + POWER(ABS(w1.Lat - w2.Lat), 2))*60) AS Distance
FROM Weather w1 LEFT JOIN Weather w2 USING (ID)
WHERE w1.Marker="Cloud" AND w2.Marker="Wind"
ORDER BY Distance DESC
LIMIT 1
Assuming you just want the closest result, I added a LIMIT 1 to restrict what's returned.
On a side note, this method of finding distance between two lat/lon pairs is unlikely to give you good results for even fairly small changes. There are methods for approximating these distances...