Query SQL per avere una funzione geojson completa da PostGIS?


35

Vorrei ottenere una funzione geojson con proprietà di PostGIS. Ho trovato un esempio per avere una raccolta di funzionalità ma non riesco a farlo funzionare solo per una funzione.

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;

finora ho provato a modificare la query di raccolta delle caratteristiche dell'esempio. ma l'output non è valido.


Ho dovuto fare una prova di concetto per un'altra app, quindi ho messo insieme questo repository che, in parte, usa le risposte da qui. Speriamo che aiuti a iniziare con questa roba - trovala qui: pg-us-census-poc
zak,

Risposte:


59

Questo può essere fatto in modo un po 'più semplice con json_build_objectPostgreSQL 9.4+, che consente di creare un JSON fornendo argomenti chiave / valore alternati. Per esempio:

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;

Le cose vanno ancora meglio in PostgreSQL 9.5+, dove vengono aggiunti alcuni nuovi operatori per il jsonbtipo di dati ( documenti ). Ciò semplifica l'impostazione di un oggetto "proprietà" che contiene tutto tranne l'id e la geometria .

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;

Vuoi fare un FeatureCollection? Basta avvolgere il tutto con 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;

1
Questa funzionalità da sola mi fa tentare di aggiornare da 9.3.5 a 9.5.3 questa mattina. Se solo fosse semplice come regexp_replace(current_setting('server_version'),'(\d)\.(\d)\.(\d)','\1.\3.\2')...
GT.

1
OK: tutto aggiornato ora (anche se non è possibile ottenere 9.5.3 per essere eseguito come servizio Windoze). Comunque ... una piccola cosa sull'esempio dato - il secondo json_build_objectha due punti invece di virgole.
GT.

non funziona per me su pg v9.6
Pak,

2
Per completezza, è probabile che i vertici della geometria non siano nell'ordine corretto per il geojson rigoroso (la regola della mano destra), per correggere ciò, possiamo riordinare i vertici nel geom con ST_ForcePolygonCCW - postgis.net/docs/manual-dev/ ST_ForcePolygonCCW.html
chrismarx,

1
@chrismarx questo è un buon punto e solleva la questione se la ST_AsGeoJSONfunzione di PostGIS debba essere modificata per correggere da sola l'orientamento.
dbaston,

21

Questa risposta potrebbe essere utilizzata con la versione PostgreSQL anteriore alla 9.4. Usa la risposta di dbaston per PostgreSQL 9.4+

La query è la seguente: (dove si 'GEOM'trova il campo della geometria, idil campo da includere nelle proprietà json, shapefile_featureil nome della tabella ed 489445è l'id della funzione desiderata)

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;

produzione:

{
   "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
   }
}

dal momento che lo hai spostato dal corpo della tua domanda alla risposta, significa che questa query e il risultato ora funzionano correttamente? Eseguendo questo tramite GeoJSONLint , non sembra ancora fornire un output valido.
Ryan Dalton,

1
Fantastico, ha senso. Immagino di non aver guardato abbastanza da vicino. Sentiti libero di contrassegnarlo come "Accettato" quando GIS.SE gli consente di chiudere la domanda. Grazie!
Ryan Dalton,

1
Non è solo GeoJSONLint che non accetta le virgolette singole. JSON non riconosce nemmeno formalmente le virgolette singole. Se un parser li riconosce, è un'estensione non standard e probabilmente è meglio evitarla.
jpmc26,

@BelowtheRadar Quello è un dict, non JSON. Sono cose molto diverse. JSON è una stringa. Sempre. È un formato di testo, allo stesso modo in cui XML è solo un formato di testo. A dictè un oggetto in memoria.
jpmc26,

5

Solo una leggera correzione alla risposta di dbaston (vorrei commentare ma non ho punti) Devi lanciare l'output di ST_AsGeoJSON come json (il ::jsoncoso):

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;

Altrimenti il ​​membro della geometria sarà una stringa. Questo non è valido GeoJSON


4

La risposta di @ dbaston è stata modificata di recente da @John Powell aka Barça, e produce geojson non validi da parte mia. Come modificato, l'aggregazione sulle funzionalità restituisce ogni funzione nidificata all'interno di un oggetto json, che non è valida.

Non ho la reputazione di commentare direttamente la risposta, ma l'ultimo jsonb_agg dovrebbe essere nella colonna "funzionalità" e non nella sottoquery "caratteristiche". L'aggregazione sul nome della colonna (o "features.feature" se lo trovi più ordinato) mette tutti gli elementi direttamente nella matrice "features" dopo l'aggregazione, che è la strada giusta da percorrere.

Quindi, il seguente, che è abbastanza simile alla risposta di @ dbaston com'era fino a poche settimane fa (più la correzione di @Jonh Powell alla denominazione delle subquery) funziona:

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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.