Permintaan SQL untuk memiliki fitur geojson lengkap dari PostGIS?

35

Saya ingin mendapatkan fitur geojson dengan properti dari PostGIS. Saya telah menemukan contoh untuk memiliki koleksi fitur tetapi saya tidak dapat membuatnya berfungsi hanya untuk fitur.

SELECT row_to_json(fc)
 FROM ( SELECT 'FeatureCollection' As type, array_to_json(array_agg(f)) As features
 FROM (SELECT 'Feature' As type
    , ST_AsGeoJSON(lg.geog)::json As geometry
    , row_to_json(lp) As properties
   FROM locations As lg 
         INNER JOIN (SELECT loc_id, loc_name FROM locations) As lp 
       ON lg.loc_id = lp.loc_id  ) As f )  As fc;

sejauh ini saya mencoba mengubah kueri kumpulan fitur dari contoh. tetapi hasilnya tidak valid.

Di bawah Radar
sumber
Saya harus melakukan pembuktian konsep untuk aplikasi lain jadi kumpulkan repo ini yang sebagian menggunakan jawaban dari sini. Semoga membantu memulai dengan hal ini - temukan di sini: pg-us-census-poc
zak

Jawaban:

59

Ini dapat dilakukan sedikit lebih sederhana dengan json_build_objectdi PostgreSQL 9.4+, yang memungkinkan Anda membangun JSON dengan memasok argumen kunci / nilai yang bergantian. Sebagai contoh:

SELECT json_build_object(
    'type',       'Feature',
    'id',         gid,
    'geometry',   ST_AsGeoJSON(geom)::json,
    'properties', json_build_object(
        'feat_type', feat_type,
        'feat_area', ST_Area(geom)::geography
     )
 )
 FROM input_table;

Segalanya menjadi lebih baik di PostgreSQL 9.5+, di mana beberapa operator baru ditambahkan untuk jsonbtipe data ( dokumen ). Ini membuatnya mudah untuk mengatur objek "properti" yang berisi segalanya kecuali id ​​dan geometri .

SELECT jsonb_build_object(
    'type',       'Feature',
    'id',         gid,
    'geometry',   ST_AsGeoJSON(geom)::jsonb,
    'properties', to_jsonb(row) - 'gid' - 'geom'
) FROM (SELECT * FROM input_table) row;

Ingin membuat FeatureCollection? Bungkus semuanya dengan jsonb_agg:

SELECT jsonb_build_object(
    'type',     'FeatureCollection',
    'features', jsonb_agg(features.feature)
)
FROM (
  SELECT jsonb_build_object(
    'type',       'Feature',
    'id',         gid,
    'geometry',   ST_AsGeoJSON(geom)::jsonb,
    'properties', to_jsonb(inputs) - 'gid' - 'geom'
  ) AS feature
  FROM (SELECT * FROM input_table) inputs) features;
dbaston
sumber
1
Fungsionalitas ini sendiri membuat saya berjuang untuk meningkatkan dari 9.3.5 ke 9.5.3 pagi ini. Kalau saja itu sesederhana regexp_replace(current_setting('server_version'),'(\d)\.(\d)\.(\d)','\1.\3.\2')...
GT.
1
OK - semua ditingkatkan sekarang (walaupun tidak bisa mendapatkan 9.5.3 untuk dijalankan sebagai layanan Windoze). Bagaimanapun ... satu hal kecil tentang contoh yang diberikan - yang kedua json_build_objectmemiliki titik dua bukan koma.
GT.
tidak bekerja untuk saya di hal v9.6
Pak
2
Untuk kelengkapan, kemungkinan bahwa simpul geometri tidak berada dalam urutan yang benar untuk geojson ketat (aturan tangan kanan), untuk memperbaiki itu, kita dapat menyusun ulang simpul dalam geom dengan ST_ForcePolygonCCW - postgis.net/docs/manual-dev/ ST_ForcePolygonCCW.html
chrismarx
1
@ chrismarx ini adalah poin yang bagus dan memunculkan masalah apakah ST_AsGeoJSONfungsi PostGIS harus dimodifikasi untuk memperbaiki orientasi sendiri.
dbaston
21

Jawaban ini dapat digunakan dengan versi PostgreSQL anterior hingga 9.4. Gunakan jawaban dbaston untuk PostgreSQL 9.4+

Kueri adalah sebagai berikut: (di mana 'GEOM'bidang geometri, idbidang untuk dimasukkan dalam properti json, shapefile_featurenama tabel, dan 489445id dari fitur yang diinginkan)

SELECT row_to_json(f) As feature \
     FROM (SELECT 'Feature' As type \
     , ST_AsGeoJSON('GEOM')::json As geometry \
     , row_to_json((SELECT l FROM (SELECT id AS feat_id) As l)) As properties \
     FROM shapefile_feature As l WHERE l.id = 489445) As f;

keluaran:

{
   "geometry":{
      "type":"MultiPolygon",
      "coordinates":[
         [
            [
               [
                  -309443.24253826,
                  388111.579584133
               ],
               [
                  -134666.391073443,
                  239616.414560895
               ],
               [
                  -308616.222736376,
                  238788.813082666
               ],
               [
                  -309443.24253826,
                  388111.579584133
               ]
            ]
         ]
      ]
   },
   "type":"Feature",
   "properties":{
      "feat_id":489445
   }
}
Di bawah Radar
sumber
karena Anda memindahkan ini dari isi pertanyaan Anda ke jawabannya, apakah ini berarti pertanyaan dan hasil ini sekarang berfungsi dengan benar? Menjalankan ini melalui GeoJSONLint , tampaknya masih tidak memberikan output yang valid.
RyanDalton
1
Bagus, itu masuk akal. Saya kira saya tidak melihat cukup dekat. Jangan ragu untuk menandai ini sebagai "Diterima" begitu GIS.SE memungkinkannya untuk menutup pertanyaan. Terima kasih!
RyanDalton
1
Bukan hanya GeoJSONLint yang tidak menerima tanda kutip tunggal. JSON juga tidak secara formal mengenali tanda kutip tunggal. Jika parser mengenalinya, itu adalah ekstensi yang tidak standar dan mungkin sebaiknya dihindari.
jpmc26
@BelowtheRadar Itu adalah dict, bukan JSON. Mereka adalah hal yang sangat berbeda. JSON adalah sebuah string. Selalu. Ini format teks, dengan cara yang sama XML hanya format teks. A dictadalah objek dalam memori.
jpmc26
5

Hanya sedikit koreksi pada jawaban dbaston (saya ingin berkomentar tapi saya tidak punya poin) Anda harus menggunakan output ST_AsGeoJSON sebagai json (the ::jsonthingie):

SELECT json_build_object(
  'type',       'Feature',
  'id',         gid,
  'geometry',   ST_AsGeoJSON(geom)::json,
  'properties', json_build_object(
    'feat_type', feat_type,
    'feat_area', ST_Area(geom)::geography
  )
)
FROM input_table;

Kalau tidak, anggota geometri akan menjadi string. Itu tidak sah GeoJSON

JavPL
sumber
4

@ dbaston jawaban telah dimodifikasi akhir-akhir ini oleh @ John Powell alias Barça, dan itu menghasilkan geojsons tidak valid pada akhirnya. Saat dimodifikasi, agregasi pada fitur mengembalikan setiap fitur yang bersarang di dalam objek json, yang tidak valid.

Saya tidak memiliki reputasi untuk mengomentari jawabannya secara langsung, tetapi jsonb_agg terakhir harusnya ada di kolom "fitur" dan bukan pada subquery "fitur". Menggabungkan pada nama kolom (atau "fitur.fitur" jika Anda menemukannya lebih rapi) menempatkan setiap elemen langsung dalam array "fitur" setelah agregasi, yang merupakan cara yang tepat untuk pergi.

Jadi berikut ini, yang sangat mirip dengan jawaban @ dbaston seperti sampai beberapa minggu yang lalu (ditambah koreksi @Jonh Powell untuk penamaan subquery) tidak berfungsi:

SELECT jsonb_build_object(
  'type',     'FeatureCollection',
  'features', jsonb_agg(feature)
)
FROM (
  SELECT jsonb_build_object(
    'type',       'Feature',
    'id',         gid,
    'geometry',   ST_AsGeoJSON(geom)::jsonb,
    'properties', to_jsonb(inputs) - 'gid' - 'geom'
  ) AS feature
  FROM (
    SELECT * FROM input_table
  ) inputs
) features;
jufaua
sumber