jon.m
11/14/2021, 5:45 PMScott P
11/14/2021, 6:33 PMgeolib
(for JS).
If you've got a set of data in Postgres and want to search for e.g. nearest points from the user location, there's a few things to setup. I've done this for things like bus stops, since users will usually want to know where bus stops are within an area as opposed to remembering a street name.
1. Ensure that each row has a latitude
and longitude
property and that all rows have valid data for these columns.
2. Ensure that you've enabled (or installed, if self-hosting) the postgis
extensions
3. Update your table so that it has a geometry
column of type extensions.geometry
4. Update every row in the table to create the geometry data (in this example, the table is called `some_table`:
sql
UPDATE public.some_table SET geometry = extensions.ST_SetSRID(extensions.ST_MakePoint(longitude, latitude), 4326);
Scott P
11/14/2021, 6:33 PMsql
CREATE OR REPLACE FUNCTION public.search_locations_by_distance(
in_latitude real,
in_longitude real,
max_distance_in_meters integer,
result_limit integer DEFAULT 20)
RETURNS TABLE(
atco_code text,
naptan text,
common_name text,
short_common_name text,
landmark text,
street text,
crossing text,
bearing text,
longitude real,
latitude real,
geographic_area text,
distance double precision
)
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
ROWS 1000
AS $BODY$
BEGIN RETURN QUERY
SELECT *
FROM public.some_table as stops,
extensions.ST_Distancesphere(
stops.geometry,
extensions.ST_MakePoint(in_longitude, in_latitude)
) as distance
WHERE extensions.ST_Distancesphere(
stops.geometry,
extensions.ST_MakePoint(in_longitude, in_latitude)
) < LEAST (max_distance_in_meters, 5000)
ORDER BY distance ASC
LIMIT LEAST (result_limit, 100);
END;
$BODY$;
In that example, it allows me to specify a latitude, a longitude, a maximum distance, and a result limit. It also enforces a maximum distance of 5000 meters and 100 results using the LEAST
function.
After you've gone through that setup, you're able to call it with the JS library like this:
js
SupabaseClient.rpc("search_locations_by_distance", {
in_latitude: <user latitude>,
in_longitude: <user longitude>,
max_distance_in_meters: 800,
})
result_limit
will default to 20 if not specified.Scott P
11/14/2021, 6:42 PMjon.m
11/14/2021, 7:10 PMScott P
11/14/2021, 7:14 PMjon.m
11/14/2021, 7:17 PMjon.m
11/21/2021, 11:50 PMburggraf
11/22/2021, 3:31 PMburggraf
11/22/2021, 3:34 PMWHERE
earth_box(ll_to_earth(${lat}, ${lng}), ${radius}) @> ll_to_earth("Latitude", "Longitude")
AND earth_distance(ll_to_earth(${lat}, ${lng}),
ll_to_earth("Latitude", "Longitude")) < ${radius}
ORDER BY distance LIMIT 200
burggraf
11/22/2021, 3:36 PMlat
and lng
, the fields in the database are named Latitude
and Longitude
, and you also pass it radius
which is in meters, which would be the max search radius.burggraf
11/22/2021, 3:36 PMEARTHDISTANCE
extension!