Requête SQL pour avoir une fonctionnalité complète de géojson de PostGIS?

35

Je souhaite une fonctionnalité geojson avec les propriétés de PostGIS. J'ai trouvé un exemple pour avoir une collection de fonctionnalités, mais je ne peux pas le faire fonctionner pour une fonctionnalité uniquement.

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;

Jusqu'à présent, j'ai essayé de modifier la requête de collection d'objets de l'exemple. mais la sortie n'est pas valide.

Au-dessous du radar
la source
Je devais faire une preuve de concept pour une autre application afin de composer ce rapport qui utilise en partie les réponses fournies ici. Aide Si tout va bien commencer avec ce genre de choses - le trouver ici: pg-nous-census-poc
zak

Réponses:

59

Cela peut être fait un peu plus simplement avec json_build_objectPostgreSQL 9.4+, qui vous permet de construire un JSON en fournissant des arguments clé / valeur en alternance. Par exemple:

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;

Les choses s'améliorent encore dans PostgreSQL 9.5+, où de nouveaux opérateurs sont ajoutés pour le jsonbtype de données ( docs ). Cela facilite la configuration d'un objet "propriétés" qui contient tout sauf l'id et la géométrie .

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;

Vous voulez faire une FeatureCollection? Terminez le tout avec 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
la source
1
Cette fonctionnalité seule me permet de passer de 9.3.5 à 9.5.3 ce matin. Si seulement c'était aussi simple que regexp_replace(current_setting('server_version'),'(\d)\.(\d)\.(\d)','\1.\3.\2')...
GT.
1
OK - tout est mis à jour maintenant (bien que impossible de faire fonctionner 9.5.3 en tant que service Windoze). Quoi qu'il en soit ... une petite chose à propos de l'exemple donné - la seconde json_build_objecta des deux-points à la place de virgules.
GT.
ne fonctionne pas pour moi sur pg v9.6
Pak
2
Pour être complet, il est probable que les sommets de la géométrie ne soient pas dans le bon ordre pour geojson strict (règle de la main droite). Pour rectifier cela, nous pouvons réorganiser les sommets de la géom avec ST_ForcePolygonCCW - postgis.net/docs/manual-dev/ ST_ForcePolygonCCW.html
chrismarx
1
@chrismarx c'est un bon point et soulève la question de savoir si la ST_AsGeoJSONfonction de PostGIS doit être modifiée pour corriger l'orientation par elle-même.
dbaston
21

Cette réponse pourrait être utilisée avec la version de PostgreSQL antérieure à la 9.4. Utilisez la réponse de dbaston pour PostgreSQL 9.4+

La requête est la suivante: (où 'GEOM'est le champ de géométrie, idle champ à inclure dans les propriétés de JSON, shapefile_featurele nom de la table et 489445l'identifiant de l'entité recherchée)

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;

sortie:

{
   "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
   }
}
Au-dessous du radar
la source
puisque vous avez déplacé ceci du corps de votre question à la réponse, cela signifie-t-il que cette requête et ce résultat fonctionnent maintenant correctement? En exécutant ceci via GeoJSONLint , il ne semble toujours pas donner de sortie valide.
RyanDalton
1
Génial, ça a du sens. Je suppose que je n'ai tout simplement pas regardé assez attentivement. N'hésitez pas à marquer ceci comme "Accepté" une fois que GIS.SE lui permettra de clore la question. Merci!
RyanDalton
1
GeoJSONLint n’accepte pas que les guillemets simples. JSON ne reconnaît pas non plus formellement les guillemets simples. Si un analyseur les reconnaît, il s’agit d’une extension non standard qui devrait probablement être évitée.
Jpmc26
@BelowtheRadar C'est un dictJSON, pas. Ce sont des choses très différentes. JSON est une chaîne. Toujours. C'est un format de texte, de la même manière que XML n'est qu'un format de texte. A dictest un objet en mémoire.
jpmc26
5

Juste une légère correction à la réponse de dbaston (je voudrais commenter mais je n'ai pas de points). Vous devez convertir la sortie de ST_AsGeoJSON en 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;

Sinon, le membre géométrique sera une chaîne. Ce n'est pas valide GeoJSON

JavPL
la source
4

La réponse de @ dbaston a été modifiée récemment par @John Powell, alias Barça, et elle produit des geojsons non valides de mon côté. Lorsqu’elle est modifiée, l’agrégation de fonctions renvoie chaque fonction imbriquée dans un objet JSON, qui n’est pas valide.

Je n'ai pas la réputation de commenter directement la réponse, mais le fichier jsonb_agg final doit figurer dans la colonne "feature" et non dans la sous-requête "features". L'agrégation sur le nom de la colonne (ou "features.feature" si vous la trouvez plus nette) place chaque élément directement dans le tableau "features" après l'agrégation, ce qui est la bonne façon de procéder.

Donc, ce qui suit, qui est assez similaire à la réponse de @ dbaston telle qu'elle l'était il y a quelques semaines (plus la correction de @Jonh Powell en nommant les sous-requêtes) fonctionne:

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
la source