6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

HasuraでPostGISにGraphQLする

Last updated at Posted at 2021-01-01

Hasuraって?

HasuraとはPostgreSQLやMySQLに直接繋がるGraphQLエンジンであり、API Gatewayでもあるプロダクト。
SaaS版とOSS(コミュニティ)版があり、SaaS版でもFree tierが用意されているので簡単に試すことができる。

元々はPostgreSQLをターゲットに開発されており、後追いでMySQLにも対応したみたい。

また、PostgreSQLの地理空間情報拡張機能であるPostGISにも対応しているようなので、使い勝手を見てみる。

前提条件

  • OSS版のDockerでも、SaaS版のFree tierでも良いのでHasura及びPostgreSQLの動く環境を用意しておくこと。

  • PostgreSQLでPostGISを使えるようにしておくこと

$ CREATE EXTENSION postgis;


# データ準備

## 入手

国土数値情報のサイトから東京都のバス停データを入手する。
https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-P11.html

## 変換

国土数値情報からダウンロードしたデータはShapeファイルなのでそのままではPostgreSQLに入らない。
そのため`shp2pgsql`コマンドを用いてSQLファイルにする。

shp2pgsql -s 4612 -D -i -I -W cp932 P11-10_13-jgd-g_BusStop.shp busstop > busstop.sql


## 登録

以下のようなコマンドで登録する。

psql -U -h -f busstop.sql


# GraphiQLでクエリ発行
## 全件カウントクエリ
```graphql
query BusstopAll {
  busstop_aggregate {
    aggregate {
      count
    }
  }
}

結果

{
  "data": {
    "busstop_aggregate": {
      "aggregate": {
        "count": 9446
      }
    }
  }
}

image.png

特定のポリゴンに含まれる件数をカウントするクエリ

query BusstopWithin($polygon: geometry = "{'type': 'Polygon','coordinates': [[[139.6,35.6],[139.6,35.7],[139.7,35.7],[139.7,35.6],[139.6,35.6]]]}") {
  busstop_aggregate(where: {geom: {_st_within: $polygon}}) {
    aggregate {
      count
    }
  }
}

結果

{
  "data": {
    "busstop_aggregate": {
      "aggregate": {
        "count": 822
      }
    }
  }
}

image.png

現在HasuraでサポートされているGraphQLから使えるPostGIS関数は以下の通り。

PostGIS topology operator equivalent GraphQL operator
ST_Contains _st_contains
ST_Crosses _st_crosses
ST_Equals _st_equals
ST_Intersects _st_intersects
ST_Overlaps _st_overlaps
ST_Touches _st_touches
ST_Within _st_within
ST_DWithin _st_d_within
(https://hasura.io/blog/native-support-for-postgis-topology-operators-now-in-graphql-engine/)

関数を呼び出す

関数の作成

2点(xmin, ymin, xmax, ymax)の座標からBBOXを作り、そこに含まれるバス停を返す関数を作る。
動作としては上記のST_Withinを使うのと同じ結果。

CREATE OR REPLACE FUNCTION busstop_filter_bbox(double precision, double precision, double precision, double precision)
RETURNS SETOF busstop AS $$
    SELECT *
    FROM busstop
    WHERE geom && ST_MakeEnvelope($1, $2, $3, $4, 4326);
$$ LANGUAGE sql STABLE;

※関数宣言はSTABLEで行うこと

GraphQLで呼び出し

query MyQuery {
  busstop_filter_bbox_aggregate(
    args: {
      arg_1: 139.6,
      arg_2: 35.6,
      arg_3: 139.7,
      arg_4: 35.7}) {
    aggregate {
      count
    }
  }
}

結果

{
  "data": {
    "busstop_filter_bbox_aggregate": {
      "aggregate": {
        "count": 822
      }
    }
  }
}

まとめ

  • PostGIS関数のいくつかは標準サポートされているので簡単なフィルタリングなら何もしなくても使える
  • 複雑なクエリを発行したい場合はPostgreSQLの関数を作ることによって何とかなりそう
    • テーブル+標準関数で難しい場合はビューまたは関数で乗り切る2段構えで大体の要件はクリアできそう

とにかくHasuraが優秀すぎる。。。

6
5
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
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?