SQL-запрос, чтобы иметь полную функцию Geojson от PostGIS?

35

Я хотел бы получить функцию геоджон со свойствами PostGIS. Я нашел пример, чтобы иметь коллекцию функций, но я не могу заставить ее работать только для функции.

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;

до сих пор я пытался изменить запрос коллекции объектов в примере. но вывод не действителен.

Ниже радара
источник
Я должен был сделать проверку концепции для другого приложения, так что соберите этот репозиторий, который частично использует ответы отсюда. Надеюсь, поможет начать работу с этим материалом - найдите его здесь: pg-us-census-poc
Зак

Ответы:

59

Это можно сделать немного проще с помощью json_build_objectPostgreSQL 9.4+, который позволяет создавать JSON, предоставляя переменные аргументы ключ / значение. Например:

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;

Ситуация становится еще лучше в PostgreSQL 9.5+, где добавлены некоторые новые операторы для jsonbтипа данных ( docs ). Это облегчает настройку объекта «свойств», который содержит все, кроме идентификатора и геометрии .

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;

Хотите сделать FeatureCollection? Просто оберните все это 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
источник
1
Одна только эта функциональность заставляет меня обновляться с 9.3.5 до 9.5.3 этим утром. Если бы это было так просто, как regexp_replace(current_setting('server_version'),'(\d)\.(\d)\.(\d)','\1.\3.\2')...
GT.
1
ОК - все обновлено сейчас (хотя 9.5.3 не может работать как служба Windoze). Во всяком случае ... одна маленькая вещь о приведенном примере - у второго json_build_objectдвоеточия вместо запятых.
GT.
у меня не работает на pg v9.6
Пак
2
Для полноты, вероятно, что вершины геометрии не в правильном порядке для строгого геойсона (правило правой руки), чтобы исправить это, мы можем изменить порядок вершин в геом с помощью ST_ForcePolygonCCW - postgis.net/docs/manual-dev/ ST_ForcePolygonCCW.html
chrismarx
1
@ chrismarx - это хороший момент, и возникает вопрос о том, ST_AsGeoJSONследует ли модифицировать функцию PostGIS для самостоятельной коррекции ориентации.
dbaston
21

Этот ответ можно использовать с версией PostgreSQL, предшествующей 9.4. Используйте ответ dbaston для PostgreSQL 9.4+

Запрос следующий: (где 'GEOM'находится поле геометрии, idполе для включения в свойства json, shapefile_featureимя таблицы и 489445идентификатор требуемой функции)

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;

выход:

{
   "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
   }
}
Ниже радара
источник
так как вы переместили это из тела вашего вопроса в ответ, означает ли это, что этот запрос и результат теперь работают правильно? Запуская это через GeoJSONLint , он все еще не дает корректный вывод.
RyanDalton
1
Отлично, это имеет смысл. Я думаю, я просто не выглядел достаточно внимательно. Не стесняйтесь пометить это как «Принятый», как только GIS.SE позволяет закрыть вопрос. Благодарность!
RyanDalton
1
Это не просто GeoJSONLint, который не принимает одинарные кавычки. JSON также официально не распознает одинарные кавычки. Если какой-либо парсер их распознает, это нестандартное расширение, и, вероятно, его лучше избегать.
jpmc26
@ BelowtheRadar Это dictне JSON. Это очень разные вещи. JSON - это строка Всегда. Это текстовый формат, точно так же, как XML это просто текстовый формат. А dict- это объект в памяти.
jpmc26
5

Просто небольшая поправка к ответу dbaston (я бы прокомментировал, но у меня нет баллов). Вам нужно преобразовать вывод ST_AsGeoJSON в json ( ::jsonштука):

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;

В противном случае элемент геометрии будет строкой. Это не верно GeoJSON

JavPL
источник
4

@ dbaston в ответ был изменен в последнее время по @John Пауэлл ака Барсой, и он производит недопустимые geojsons на моем конце. После изменения агрегация объектов возвращает каждый объект, вложенный в объект json, что недопустимо.

У меня нет репутации, чтобы комментировать непосредственно ответ, но окончательный jsonb_agg должен быть в столбце «функция», а не в подзапросе «функции». Агрегирование по имени столбца (или «features.feature», если вы находите его более точным) помещает каждый элемент прямо в массив «features» после агрегации, и это правильный путь.

Так что следующее, что очень похоже на ответ @ dbaston, как это было до нескольких недель назад (плюс исправление @Jonh Powell для именования подзапросов), работает:

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
источник