LoginSignup
5
1

More than 1 year has passed since last update.

PostGIS と Hasura でサクッと範囲検索 API の作成

Posted at

Postgres で Function 定義

landmark テーブルで、指定した中心点と半径に含まれるレコードを、近い順に並べ抽出する。

  • landmarks テーブルを作成
  • array_to_geography() Function を作成する。
    • array ([longitude, latitude])を geography に変換する。
  • geo_landmarks() Function では geography の値を使用し、パラメーターの円(中心点と半径)に含まれる landmark を円の中心点より近い順に並べて返す。
create table landmarks (
    id uuid default gen_random_uuid(),
    name text not null,
    description text,
    point double precision[],
    geopoint geography(point, 4326),
    location jsonb not null default '{}',
    primary key (id)
);

create or replace function array_to_geography() returns trigger as $$
begin
    new.geopoint = st_setsrid(st_point(new.point[1], new.point[2]), 4326)::geography;
    new.location = json_build_object('longitude', new.point[1], 'latitude', new.point[2]);
    return new;
end;
$$ language plpgsql;

create trigger trigger_array_to_geography
before insert or update on landmarks
for each row execute procedure array_to_geography();

create or replace function public.geo_landmarks(
    latitude double precision,
    longitude double precision,
    radius integer
) returns setof public.landmarks as $$

    select 
        id,
        name,
        description,
        point,
        geopoint,
        case
            when point is null then '{}'::jsonb
            else json_build_object(
                'longitude',
                point[1],
                'latitude',
                point[2],
                'distance',
                st_distance(st_point(longitude, latitude)::geography, geopoint)
            )::jsonb
        end as location
    from
        landmarks
    where
        st_dwithin(geopoint, st_point(longitude, latitude)::geography, radius)
    order by
        st_distance(st_point(longitude, latitude)::geography, geopoint),
        name asc
    ;

$$ language sql stable;

よくよく見ると、それ必要?といった所もあるが大目に見る。

上記定義と Hasura で API を試す

Hasura を起動する

git clone https://github.com/high-u/tryout-hasura.git
cd tryout-hasura/postgis

docker compose up -d

しばし待つ...しばし待つ...

ブラウザで Hasura を開く

image.png

GraphQL に

query landmarksIncludedInCircle(
  $latitude: float8 = "",
  $longitude: float8 = "",
  $radius: Int = 100
) {
  landmarks: geo_landmarks(args: {
    latitude: $latitude,
    longitude: $longitude,
    radius: $radius
  }) {
    id
    name
    location
  }
}

QUERY VARIABLES に

{
  "latitude": 35.65867828258049,
  "longitude": 139.7454000428654,
  "radius": 500
}

image.png
を押すと API が実行されレスポンスが表示される。
そもそもどんなデータが登録されているかは、ここで確認。

後始末

docker compose down -v

あとがき

大量のアクセスをさばく必要がある場合には要注意だが、PostGIS を利用した距離計算付きの API が GraphQL としてあっという間に構築できることに感動した。

謝辞

下記記事に多くを学ばせていただきました。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1