แบบสอบถาม 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;

จนถึงตอนนี้ฉันพยายามแก้ไขเคียวรีการรวบรวมคุณลักษณะของตัวอย่าง แต่เอาต์พุตไม่ถูกต้อง


ฉันต้องพิสูจน์แนวคิดสำหรับแอปอื่นดังนั้นรวบรวม repo นี้ซึ่งส่วนหนึ่งใช้คำตอบจากที่นี่ หวังว่าจะช่วยให้เริ่มต้นกับสิ่งนี้ - ค้นหาได้ที่นี่: pg-us-census-poc
zak

คำตอบ:


59

สิ่งนี้สามารถทำได้ง่ายขึ้นอีกเล็กน้อยjson_build_objectใน PostgreSQL 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ประเภทข้อมูล ( เอกสาร ) นี้จะทำให้มันง่ายต่อการตั้งค่า "คุณสมบัติ" วัตถุที่มีทุกอย่าง แต่ 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
เพื่อความสมบูรณ์อาจเป็นไปได้ว่าจุดยอดรูปทรงเรขาคณิตนั้นไม่อยู่ในลำดับที่ถูกต้องสำหรับ geojson ที่เข้มงวด (กฎมือขวา) เพื่อแก้ไขว่าเราสามารถเรียงลำดับจุดยอดใน geom ด้วย 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 เป็นเพียงรูปแบบข้อความ A dictคือวัตถุในหน่วยความจำ
jpmc26

5

เพียงแค่การแก้ไขเล็กน้อยเพื่อตอบ dbaston (ฉันจะแสดงความคิดเห็น แต่ฉันไม่มีคะแนน) คุณจำเป็นต้องแสดงผลลัพธ์ของ ST_AsGeoJSON เป็น 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;

มิฉะนั้นสมาชิกรูปทรงเรขาคณิตจะเป็นสตริง ไม่ถูกต้อง GeoJSON


4

@ คำตอบของ dbastonได้รับการแก้ไขเมื่อเร็ว ๆ นี้โดย @John Powell aka Barçaและสร้าง 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;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.