SQL-запит, щоб мати повну функцію geojson від PostGIS?


35

Я хотів би отримати функцію geojson з властивостями від 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
zak

Відповіді:


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 ). Це полегшує налаштування об’єкта "властивості", який містить усе, крім id та геометрії .

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;

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
Pak

2
Для повноти, ймовірно, що вершини геометрії не в правильному порядку для суворого геойсона (правило праворуч), щоб виправити це, ми можемо впорядкувати вершини в геометрії за допомогою ST_ForcePolygonCCW - postgis.net/docs/manual-dev/ ST_ForcePolygonCCW.html
chrismarx

1
@chrismarx - це сприятливий момент і ставить питання про те, чи ST_AsGeoJSONслід змінювати функцію PostGIS, щоб самостійно виправити орієнтацію.
дбастон

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 - це лише текстовий формат. A 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


4

@ Dbaston в відповідь був змінений в останній час по @John Пауелл ака Барсою, і він виробляє неприпустимі geojsons на моєму кінці. Як змінено, агрегація за функціями повертає кожну функцію, вкладену в об'єкт json, який є недійсним.

У мене немає репутації коментувати відповідь безпосередньо, але остаточний jsonb_agg повинен знаходитись у стовпці "особливість", а не в підзапиті "особливості". Агрегуючи по імені стовпця (або "Features.feature", якщо ви вважаєте його акуратнішим), кожен елемент проставляє в масив "особливості" після агрегації, що є правильним шляхом.

Отже, наступне, що дуже схоже на відповідь @ 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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.