【MySQL】MySQLにFeatureCollection型のGeoJSONの情報を保持させる

  • 2022年9月20日
  • SQL

 MySQL には空間データを扱う仕組みがあり、この中には地理データである GeoJSON を扱う仕組みも含まれます。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 12.17.11 空間 GeoJSON 関数
MySQL :: MySQL 8.0 Reference Manual :: 12.17.11 Spatial GeoJSON Functions

 MySQL8.0 は GeoJSON の概ねの型に対応しているのですが、残念ながら Feature と FeatureCollection には対応していません。

GeoJSON では、MySQL でサポートされているものと同じジオメトリデータ型または地理データ型がサポートされます。 ジオメトリオブジェクトが抽出される点を除き、フィーチャおよび FeatureCollection オブジェクトはサポートされていません。 CRS のサポートは SRID を識別する値に制限されています。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 12.17.11 空間 GeoJSON 関数 より引用

 FeatureCollection は次の様に地理情報に密に情報を紐づけられる形式であり、これが使えると表現可能なものが増えます。

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [
                        [100.0, 0.0],
                        [101.0, 0.0],
                        [101.0, 1.0],
                        [100.0, 1.0],
                        [100.0, 0.0]
                    ]
                ]
            },
            "properties": {
                "fill": "rgba(0, 128, 255, 0.5)",
                "border": "rgba(0, 128, 255, 0.5)"
            }
        },{
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [100.5, 0.5]
            },
            "properties": {
                "markerImg": "/img.example.com/marker.webp"
            }
        }
    ]
}

 この FeatureCollection を情報量を落とさず MySQL 内に地理情報として保存する方法を紹介します。

 MySQL は FeatureCollection に対応していませんが、これは完全に対応していないといった程度で FeatureCollection 型の GeoJSON を読み込んで GeometryCollection として保存することはできます。これを利用して FeatureCollection をJSON型カラムに格納し、格納した FeatureCollection を元に GeometryCollection として空間データを保存する方法が使えます。これを実現できるカラムの定義が次です。

geojson_raw      json not null comment 'GeoJSONをそのまま格納',
geojson_geometry geometrycollection as (ST_GEOMFROMGEOJSON(`geojson_raw`)) stored
        comment 'ST_GEOMFROMGEOJSON 関数でGeoJSONから空間データを生成して格納'

 これにより FeatureCollection としての様々な情報を残したまま空間データとして地理情報保持することができます。これは例えば次の様に実装できます。

create table leaflet_draws
(
    leaflet_layer_id bigint unsigned auto_increment primary key
        comment '主キー',
    geojson_raw      json not null
        comment 'GeoJSONをそのまま保持する。Featureとしての情報もここが持つ',
    # ST_GEOMFROMGEOJSON 関数でGeoJSONから空間データを生成
    geojson_geometry geometrycollection as (ST_GEOMFROMGEOJSON(`geojson_raw`)) stored
        comment 'geojson_rawカラムが持つGeoJSONを元にした地理情報を保持する。各空間分析関数はここを介して使う'
) comment 'leaflet の地図上に配置した色々';
# データ挿入例
INSERT INTO leaflet_draws (geojson_raw) VALUES ('{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [100.0, 0.0],
            [101.0, 0.0],
            [101.0, 1.0],
            [100.0, 1.0],
            [100.0, 0.0]
          ]
        ]
      },
      "properties": {
        "fill": "rgba(0, 128, 255, 0.5)",
        "border": "rgba(0, 128, 255, 0.5)"
      }
    },{
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [100.5, 0.5]
      },
      "properties": {
        "markerImg": "/img.example.com/marker.webp"
      }
    }
  ]
}');
INSERT INTO leaflet_draws (geojson_raw) VALUES ('{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [-100.0, 0.0],
            [-101.0, 0.0],
            [-101.0, 2.0],
            [-100.0, 2.0],
            [-100.0, 0.0]
          ]
        ]
      },
      "properties": {
        "comment": "離れた場所にある面"
      }
    }
  ]
}');
# 空間関数使用例
# [[100.5, 0.5], [120.5, 0.5]] の線が交差する空間データを持つレコードのみを抜き出し
select leaflet_layer_id, geojson_raw from leaflet_draws
where ST_Intersects(geojson_geometry, st_geomfromgeojson('{
        "type": "LineString",
        "coordinates": [[100.5, 0.5], [120.5, 0.5]]
      }'));
# FeatureCollection部使用例
# JSON関数を使ってコメントを読み取る 
select
    leaflet_layer_id,
    JSON_UNQUOTE(`geojson_raw` -> "$.features[0].properties.comment") as comment
from leaflet_draws;

 こんな感じでリレーショナルデータベース上に空間データをそれに紐づく細かい情報込みで扱いやすい形で永続化できます。これは特にGIS(Geographic Information System)で使っているデータを過不足なく永続化するのに便利です。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG