¿Consulta SQL para tener una característica completa de geojson de PostGIS?


35

Me gustaría obtener una función geojson con propiedades de PostGIS. He encontrado un ejemplo para tener una colección de características, pero no puedo hacer que funcione solo para una característica.

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;

Hasta ahora intenté modificar la consulta de recopilación de características del ejemplo. pero el resultado no es válido.


Tuve que hacer una prueba de concepto para otra aplicación, así que prepare este repositorio que, en parte, usa las respuestas de aquí. Esperemos que ayude a comenzar con estas cosas - búsquelo aquí: pg-us-census-poc
zak

Respuestas:


59

Esto se puede hacer un poco más simplemente con json_build_objectPostgreSQL 9.4+, que le permite construir un JSON al proporcionar argumentos alternativos de clave / valor. Por ejemplo:

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;

Las cosas mejoran aún más en PostgreSQL 9.5+, donde se agregan algunos operadores nuevos para el jsonbtipo de datos ( docs ). Esto facilita la configuración de un objeto de "propiedades" que contiene todo menos la identificación y la geometría .

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;

¿Quieres hacer una FeatureCollection? Simplemente envuélvelo 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
Esta funcionalidad solo me tiene luchando para actualizar de 9.3.5 a 9.5.3 esta mañana. Si tan solo fuera tan simple como regexp_replace(current_setting('server_version'),'(\d)\.(\d)\.(\d)','\1.\3.\2')...
GT.

1
OK: todo actualizado ahora (aunque no se puede ejecutar 9.5.3 como servicio Windoze). De todos modos ... una pequeña cosa sobre el ejemplo dado: el segundo json_build_objecttiene dos puntos en lugar de comas.
GT.

no funciona para mí en la página v9.6
Pak

2
Para completar, es probable que los vértices de la geometría no estén en el orden correcto para el geojson estricto (la regla diestra), para rectificar eso, podemos reordenar los vértices en la geom con ST_ForcePolygonCCW - postgis.net/docs/manual-dev/ ST_ForcePolygonCCW.html
chrismarx

1
@chrismarx este es un buen punto y plantea la cuestión de si la ST_AsGeoJSONfunción de PostGIS debe modificarse para corregir la orientación por sí sola.
dbaston el

21

Esta respuesta podría usarse con la versión PostgreSQL anterior a 9.4. Use la respuesta de dbaston para PostgreSQL 9.4+

La consulta es la siguiente: (donde 'GEOM'está el campo de geometría, idel campo a incluir en las propiedades json, shapefile_featureel nombre de la tabla y 489445es la identificación de la característica deseada)

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;

salida:

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

dado que movió esto del cuerpo de su pregunta a la respuesta, ¿significa que esta consulta y el resultado ahora funcionan correctamente? Al ejecutar esto a través de GeoJSONLint , todavía no parece estar dando una salida válida.
RyanDalton

1
Genial, eso tiene sentido. Supongo que simplemente no miré lo suficientemente de cerca. Siéntase libre de marcar esto como "Aceptado" una vez que GIS.SE le permita cerrar la pregunta. ¡Gracias!
RyanDalton

1
No solo GeoJSONLint no acepta comillas simples. JSON tampoco reconoce formalmente comillas simples. Si algún analizador los reconoce, es una extensión no estándar y probablemente sea mejor evitarla.
jpmc26

@BelowtheRadar Eso es dict, no JSON. Son cosas muy diferentes. JSON es una cadena. Siempre. Es un formato de texto, de la misma manera que XML es solo un formato de texto. A dictes un objeto en memoria.
jpmc26

5

Solo una ligera corrección a la respuesta de dbaston (quisiera comentar pero no tengo puntos) Necesitas lanzar la salida de ST_AsGeoJSON como json (la ::jsoncosita):

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;

De lo contrario, el miembro de geometría será una cadena. Eso no es válido GeoJSON


4

La respuesta de @Dbaston ha sido modificada recientemente por @John Powell, también conocido como Barça, y produce geojsons inválidos de mi parte. Tal como se modificó, la agregación de características devuelve cada característica anidada dentro de un objeto json, que no es válida.

No tengo la reputación de comentar directamente sobre la respuesta, pero el jsonb_agg final debería estar en la columna "característica" y no en la subconsulta "características". La agregación en el nombre de la columna (o "features.feature" si lo encuentra más ordenado) coloca todos los elementos directamente en la matriz de "características" después de la agregación, que es el camino correcto.

Entonces, lo siguiente, que es bastante similar a la respuesta de @Dbaston, ya que fue hasta hace unas semanas (más la corrección de @Jonh Powell para nombrar subconsultas) funciona:

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;
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.