SQL-Abfrage für eine vollständige Geojson-Funktion von PostGIS?

35

Ich möchte ein Geojson-Feature mit Eigenschaften von PostGIS erhalten. Ich habe ein Beispiel für eine Feature-Sammlung gefunden, kann sie jedoch nicht nur für ein Feature verwenden.

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;

Bisher habe ich versucht, die Feature-Collection-Abfrage des Beispiels zu ändern. aber die Ausgabe ist ungültig.

Unter dem Radar
quelle
Ich musste einen Proof of Concept für eine andere App machen, also dieses Repo zusammenstellen, das zum Teil die Antworten von hier verwendet. Hoffentlich hilft es, mit diesem Zeug
anzufangen

Antworten:

59

Dies kann mit json_build_objectPostgreSQL 9.4+ ein bisschen einfacher gemacht werden, mit dem Sie einen JSON-Code erstellen können, indem Sie alternative Schlüssel- / Wertargumente angeben. Beispielsweise:

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;

Noch besser wird es in PostgreSQL 9.5+, wo einige neue Operatoren für den jsonbDatentyp ( docs ) hinzugefügt werden . Dies macht es einfach, ein "Eigenschaften" -Objekt einzurichten, das alles außer der ID und der Geometrie enthält .

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;

Möchten Sie eine FeatureCollection erstellen? Einfach alles einpacken mit 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
quelle
1
Allein diese Funktionalität hat mich dazu gebracht, heute Morgen ein Upgrade von 9.3.5 auf 9.5.3 durchzuführen. Wenn es nur so einfach wäre wie regexp_replace(current_setting('server_version'),'(\d)\.(\d)\.(\d)','\1.\3.\2')...
GT.
1
OK - alle wurden jetzt aktualisiert (obwohl 9.5.3 nicht als Windoze-Dienst ausgeführt werden kann). Wie auch immer ... eine Kleinigkeit zu dem gegebenen Beispiel - das zweite json_build_objecthat Doppelpunkte anstelle von Kommas.
GT.
funktioniert bei mir nicht auf pg v9.6
Pak
2
Der Vollständigkeit halber ist es wahrscheinlich, dass die Geometrie-Scheitelpunkte nicht in der richtigen Reihenfolge für strengen Geojson sind (Rechtshänder-Regel). Um dies zu korrigieren, können wir die Scheitelpunkte im Geom mit ST_ForcePolygonCCW neu anordnen. ST_ForcePolygonCCW.html
chrismarx
1
@chrismarx Dies ist ein guter Punkt und wirft die Frage auf, ob die ST_AsGeoJSONFunktion von PostGIS geändert werden sollte, um die Ausrichtung selbst zu korrigieren.
Dbaston
21

Diese Antwort könnte mit der PostgreSQL-Version vor 9.4 verwendet werden. Verwenden Sie die Antwort von dbaston für PostgreSQL 9.4+

Die Abfrage lautet wie folgt: (Wo 'GEOM'ist das Geometriefeld, iddas Feld, das in den JSON-Eigenschaften enthalten sein soll, shapefile_featureder Tabellenname und 489445die ID des gewünschten Features?)

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;

Ausgabe:

{
   "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
   }
}
Unter dem Radar
quelle
Bedeutet dies, dass diese Abfrage und das Ergebnis jetzt korrekt funktionieren, da Sie dies vom Hauptteil Ihrer Frage zur Antwort verschoben haben? Wenn Sie dies über GeoJSONLint ausführen , scheint es immer noch keine gültige Ausgabe zu geben.
RyanDalton
1
Das macht Sinn. Ich schätze, ich habe einfach nicht genau genug hingeschaut. Fühlen Sie sich frei, dies als "Akzeptiert" zu markieren, sobald GIS.SE es erlaubt, die Frage zu schließen. Vielen Dank!
RyanDalton
1
Es ist nicht nur GeoJSONLint, das keine einfachen Anführungszeichen akzeptiert. JSON erkennt auch keine einfachen Anführungszeichen. Wenn ein Parser sie erkennt, handelt es sich um eine nicht standardmäßige Erweiterung, die wahrscheinlich am besten vermieden wird.
jpmc26
@BelowtheRadar Das ist ein dict, kein JSON. Das sind sehr unterschiedliche Dinge. JSON ist eine Zeichenfolge. Immer. Es ist ein Textformat, genauso wie XML nur ein Textformat ist. A dictist ein In-Memory-Objekt.
jpmc26
5

Nur eine kleine Korrektur der Antwort von dbaston (ich würde kommentieren, aber ich habe keine Punkte). Sie müssen die Ausgabe von ST_AsGeoJSON als json (das ::jsonDing) umwandeln:

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;

Andernfalls ist das Geometriemitglied eine Zeichenfolge. Das ist kein gültiger GeoJSON

JavPL
quelle
4

Die Antwort von @ dbaston wurde kürzlich von @ John Powell aka Barça geändert, und es entstehen auf meiner Seite ungültige Geojsons. In der geänderten Form gibt die Aggregation nach Features jedes Feature zurück, das in einem ungültigen json-Objekt verschachtelt ist.

Ich habe nicht den Ruf, die Antwort direkt zu kommentieren, aber das endgültige jsonb_agg sollte in der Spalte "feature" und nicht in der Unterabfrage "features" stehen. Wenn Sie den Spaltennamen aggregieren (oder "features.feature", wenn Sie ihn übersichtlicher finden), wird jedes Element nach der Aggregation direkt in das Array "features" eingefügt. Dies ist der richtige Weg.

Das Folgende, das der Antwort von @ dbaston bis vor einigen Wochen ziemlich ähnlich ist (plus der Korrektur von @ Jonh Powell für die Benennung von Unterabfragen), funktioniert also:

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
quelle