Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What are the problem?

HasuraでPostGISにGraphQLする

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 <user> -h <host> -f busstop.sql <db name>

GraphiQLでクエリ発行

全件カウントクエリ

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が優秀すぎる。。。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
3
Help us understand the problem. What are the problem?