douji9734 2019-06-21 15:04
浏览 632

从geojson保存postgis几何类型

I have a Lealfet map in a Laravel Blade view where the user can draw shapes and markers. These features are registered in a GeoJson object, that I stringify and insert in a hidden textarea with name "geojson" to submit it to the server, within a form.

The problem is that I want to save this data as geometry type in my PostgreSQL database, using the PostGis ST_GeomFromGeoJSON() function, but I can't get it to work.

Here is what I tried for now:

$site = new Site;
$data = $request->all();
unset($data['geojson']);

foreach($data as $key=>$d)
{
   $site->$key = $d;
}

$geojson = json_decode($request->geojson);
$site->save();

DB::update('update posha_sites set geom = ST_GeomFromGeoJSON(?)
      WHERE num_site = ?
      AND city_id = ?',
   [$geojson, $request->num_site, $city_id->id]
);

Right now I am saving all my data and then trying to insert the geospatial data, as I don't know how I could use a raw query while saving the rest of my data.

When I do that I am getting this error:

Object of class stdClass could not be converted to string


EDIT

Here is the whole migration for the posha_sites table:

public function up()
{
    Schema::create('posha_sites', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->bigInteger('num_site');
        $table->string('type', 50)->nullable();
        $table->mediumText('adresse')->nullable();
        $table->string('cartes_anciennes')->nullable();
        $table->string('carte_topo')->nullable();
        $table->mediumText('cadastre_remembre')->nullable();
        $table->mediumText('cadastre_moderne')->nullable();
        $table->mediumText('cadastre_ancien')->nullable();
        $table->string('lieu_dit')->nullable();
        $table->mediumText('nature_parcelles')->nullable();
        $table->mediumText('conditions_acces')->nullable();
        $table->string('situation_administrative')->nullable();
        $table->string('altitude')->nullable();
        $table->string('relief')->nullable();
        $table->mediumText('hydrographie')->nullable();
        $table->string('geologie')->nullable();
        $table->string('vestiges_periode')->nullable();
        $table->mediumText('vestiges_nature')->nullable();
        $table->mediumText('vestiges_conservation')->nullable();
        $table->longText('plans_documents_figures')->nullable();
        $table->longText('sources_manuscrites')->nullable();
        $table->longText('sources_imprimees')->nullable();
        $table->longText('renseignement_oral')->nullable();
        $table->longText('bibliographie')->nullable();
        $table->longText('histoire')->nullable();
        $table->longText('historiographie')->nullable();
        $table->longText('description_histoire_monumentale')->nullable();
        $table->geometrycollection('geom')->nullable();
        $table->string('last_author')->nullable();
        $table->integer('tree_id')->unsigned()->nullable();
        $table->integer('parent_id')->unsigned()->nullable();
        $table->integer('city_id')->unsigned();
        $table->timestamps();
    });
}

The function ST_GeomFromGeoJSON() is in fact expecting a string so I didn't decode my $geojson variable:

$geojson = $request->geojson;

instead of:

$geojson = json_decode($request->geojson);

But I still get an error:

SQLSTATE[XX000]: Internal error:

7 ERROR: invalid GeoJson representation (SQL: update posha_sites set geom = ST_GeomFromGeoJSON({"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-0.229114,44.564488]}}]}) WHERE num_site = 248 AND city_id = 5)

Yet I tested my geojson in an online geojson validator and it seems correct.

  • 写回答

1条回答 默认 最新

  • dongliu4320 2019-06-21 22:33
    关注

    Assuming you have at least PostgreSQL version 9.3, you can use a few JSON functions and operators to extract the relevant parts of the GeoJSON specification required by ST_GeomFromGeoJSON to create geometries.

    Try the following, where you can replace the JSON in the top part:

    WITH data AS (SELECT '{ "type": "FeatureCollection",
        "features": [
          { "type": "Feature",
            "geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
            "properties": {"prop0": "value0"}
            },
          { "type": "Feature",
            "geometry": {
              "type": "LineString",
              "coordinates": [
                [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
                ]
              },
            "properties": {
              "prop0": "value0",
              "prop1": 0.0
              }
            },
          { "type": "Feature",
             "geometry": {
               "type": "Polygon",
               "coordinates": [
                 [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
                   [100.0, 1.0], [100.0, 0.0] ]
                 ]
             },
             "properties": {
               "prop0": "value0",
               "prop1": {"this": "that"}
               }
             }
           ]
         }'::json AS fc)
    
    SELECT
      row_number() OVER () AS gid,
      ST_AsText(ST_GeomFromGeoJSON(feat->>'geometry')) AS geom,
      feat->'properties' AS properties
    FROM (
      SELECT json_array_elements(fc->'features') AS feat
      FROM data
    ) AS f;
    

    Finds three geometries. The geom column has the geometry object, and the gid is the feature number. The ST_AsText function shows the WKT equivalent of each geometry. I've also included the properties or attributes that can be defined for each geometry, as is shown in the specification.

     gid |                   geom                   |              properties
    -----+------------------------------------------+--------------------------------------
       1 | POINT(102 0.5)                           | {"prop0": "value0"}
       2 | LINESTRING(102 0,103 1,104 0,105 1)      | {                                   +
         |                                          |           "prop0": "value0",        +
         |                                          |           "prop1": 0.0              +
         |                                          |           }
       3 | POLYGON((100 0,101 0,101 1,100 1,100 0)) | {                                   +
         |                                          |            "prop0": "value0",       +
         |                                          |            "prop1": {"this": "that"}+
         |                                          |            }
    (3 rows)
    

    You should assign an SRID for the geometry, using ST_SetSRID.

    Or if you simply need a single heterogeneous GEOMETRYCOLLECTION, you can make it compact like this:

    SELECT ST_AsText(ST_Collect(ST_GeomFromGeoJSON(feat->>'geometry')))
    FROM (
      SELECT json_array_elements('{ ... put JSON here ... }'::json->'features') AS feat
    ) AS f;
    
    GEOMETRYCOLLECTION(POINT(2565453.18267219 -3835048.65976031),LINESTRING(2727584.72197102 -3713449.19424187,2732476.69178127 -3992291.47342619),POLYGON((2442627.90254053 -3705499.95430853,2425506.00820465 -3886502.83728783,2555143.20817631 -3910962.68633909,2442627.90254053 -3705499.95430853)))
    

    See also Creating GeoJSON Feature Collections with JSON and PostGIS functions from the Postgres OnLine Journal, which does the opposite.

    评论

报告相同问题?

悬赏问题

  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题
  • ¥15 Python时间序列如何拟合疏系数模型
  • ¥15 求学软件的前人们指明方向🥺
  • ¥50 如何增强飞上天的树莓派的热点信号强度,以使得笔记本可以在地面实现远程桌面连接
  • ¥20 双层网络上信息-疾病传播