Node.jsでPostGISから出たGeoJSONを受ける

はじめに

ふとNode.jsでPostGISを扱えるのかなと思いました。

方針

  • PostGISはあくまでPostgreSQLのエクステンション。まずはPostgreSQLとNode.jsがつながらなければいけない。
  • ジオメトリは放っておけばWKBHEXで出てくるけどJavaScriptで扱うならJSONにした方が良いだろう。
  • ていうかPostGISからGeoJSONを出してみよう。
  • js側ではGeoJSONをJSONとして受けよう。

Node.jsとpgのインストール

Node.jsとNPMを入れ、npm install pgでpgを入れました。

GeoJSONを吐くSQL

https://qiita.com/kshigeru/items/8940ecf7f261a6b01ed0 を参照。というか引き写しです。

SELECT row_to_json(featurecollection) FROM (  
  SELECT  
    'FeatureCollection' AS type,  
    array_to_json(array_agg(feature)) AS features  
  FROM (  
    SELECT  
      'Feature' AS type,  
      ST_AsGeoJSON(geom)::json AS geometry,  
      row_to_json((  
        SELECT p FROM (  
          SELECT [プロパティ1],[プロパティ2],...  
        ) AS p  
      )) AS properties  
    FROM [テーブル]  
    [(必要なら) LIMIT 5とか]  
  ) AS feature  
) AS featurecollection;  
  • [プロパティ1],... は、プロパティで出したいカラム
  • [テーブル] は、テーブル名(geomとプロパティ1,...を持っている)
  • [(必要なら) LIMIT 5とか] の部分は、タプルに応じて非常に長い配列になるので、テストで地物数を限定する場合に追加します。
    SELECT  
      'Feature' AS type,  
      ST_AsGeoJSON(geom)::json AS geometry,  
      row_to_json((  
        SELECT p FROM (  
          SELECT [プロパティ1],[プロパティ2],...  
        ) AS p  
      )) AS properties  

では

type      | geometry | properties        |  
---------+------------|------------------|  
Feature | ジオメトリ | {プロパティ,...}|  

というタプルができます。ジオメトリはJSON型で、GeoJSON形式の文字列型からキャストしたものです。

そして、

  SELECT  
    'FeatureCollection' AS type,  
    array_to_json(array_agg(feature)) AS features  
  FROM (  
  ...  
  ) AS feature  

では、服問い合わせで出てきたタプル(複数行になりうる)をarray_agg(feature) で配列にまとめて(1行になる)、array_to_json()でJSON型にしています。

JSONを受けるjs

https://symfoware.blog.fc2.com/blog-entry-2114.html を参照。これも引き写しです。

const {Client} = require('pg');  

const client = new Client({  
  "user": (ユーザ名),  
  "host": (ホスト名),  
  "port": 5432,  
  "database": (データベース名),  
});  

client.connect();  

const query = `  
SELECT row_to_json(featurecollection) AS json FROM (  
  SELECT  
    'FeatureCollection' AS type,  
    array_to_json(array_agg(feature)) AS features  
  FROM (  
    SELECT  
      'Feature' AS type,  
      ST_AsGeoJSON(geom)::json AS geometry,  
      row_to_json((  
        SELECT p FROM (  
          SELECT [プロパティ1],[プロパティ2],...  
        ) AS p  
      )) AS properties  
    FROM [テーブル]  
    LIMIT 5  
  ) AS feature  
) AS featurecollection  
`;  

client.query(query, (err, res) => {  
  if( err == null ) {  
    // succeeded  
    let json = res.rows[0].json;  
    console.log(typeof json);  
    console.log(JSON.stringify(json));  
  }  
  else {  
    // error  
    console.log(err, res);  
  }  
  client.end();  
});  

なお、console.log(res)resを見ると、次のようになりました。

Result {  
  command: 'SELECT',  
  rowCount: 1,  
  oid: null,  
  rows: [ { json: [Object] } ],  
  fields:   
   [ Field {  
       name: 'json',  
       tableID: 0,  
       columnID: 0,  
       dataTypeID: 114,  
       dataTypeSize: -1,  
       dataTypeModifier: -1,  
       format: 'text' } ],  
  _parsers: [ [Function: bound parse] ],  
  RowCtor: null,  
  rowAsArray: false,  
  _getTypeParser: [Function: bound ] }  

データとしてはrowsプロパティを取り出せば、GeoJSONのデータをそのままJavaScriptで使えると思います。

おわりに

そのまま引き回しているだけではありますが、PostGISの地物をNode.jsに引っ張り込むことができました。

引き写しに近いのですが、フルのGeoJSONを出す方法と、Node.jsとPostgreSQLとの接続方法と、JSONがそのままJavaScriptオブジェクトで得らることとを紹介し、意外と中身はあるのではないかと思います(自画自賛)。