Find nearest location using strapi and Postgres
You'll need a distance function. You can't use the Pythagorean theorem here because Earth is a sphere. Even if you assume all your locations and users are in one cluster on Earth that's away from the poles, it still won't be right because a degree of latitude and a degree of longitude aren't the same distance except right on the Equator. Hard-coding the conversion factor (to get the formula to work right in, e.g., London) is a recipe for bugs if and when your geographic assumptions ever change.
Distance (as the crow flies) on earth is what mathematicians call great-circle distance, so we can use one of the formulas for that metric:
CREATE OR REPLACE FUNCTION
earth_dist(a_lat NUMERIC(15,12), a_lng NUMERIC(15,12),
b_lat NUMERIC(15,12), b_lng NUMERIC(15,12))
RETURNS NUMERIC(8,3) AS $$
DECLARE
cent_angle NUMERIC(8,7);
BEGIN
a_lat := radians(a_lat);
a_lng := radians(a_lng);
b_lat := radians(b_lat);
b_lng := radians(b_lng);
cent_angle := acos(sin(a_lat)*sin(b_lat)+cos(a_lat)*cos(b_lat)*cos(a_lng - b_lng));
/* Multiply by radius of earth to get distances.
Currently set to kilometers: change multiplier to use other units. */
RETURN ROUND(6371*cent_angle,3);
END;
$$
LANGUAGE plpgsql STABLE;
From there, I'm assuming in addition to collecting lat
and lng
you have some variable for the desired number of locations returned, say num_rows
. To prevent SQL injection attacks, use the PDO method, storing these variables in a parameter list that's added separately.
Assuming that's done, you could write another function that returns a query, or just call it any other way:
SELECT property_id, property_name,
earth_dist(:lat,:lng,property_lat,property_lng)
FROM properties
ORDER BY 3
LIMIT :num_rows;