Add how to on PostGIS and hstore data types (#516)

This commit is contained in:
Laurence Isla
2022-03-22 11:30:45 +01:00
committed by GitHub
parent f56373313e
commit a8034df2bf
2 changed files with 215 additions and 0 deletions
@@ -78,3 +78,217 @@ You can use other comparative filters and also `PostgreSQL special date/time inp
"due_date": "2022-02-27T06:00:00-05:00"
}
]
hstore
------
You can work with data types belonging to additional supplied modules such as `hstore <https://www.postgresql.org/docs/current/hstore.html>`_. Let's use the following table:
.. code-block:: postgres
-- Activate the hstore module in the current database
create extension if not exists hstore;
create table countries (
id int primary key,
name hstore unique
);
The ``name`` column will have the name of the country in different formats. You can insert values using the string representation for that data type, for instance:
.. tabs::
.. code-tab:: http
POST /countries HTTP/1.1
Content-Type: application/json
[
{ "id": 1, "name": "common => Egypt, official => \"Arab Republic of Egypt\", native => مصر" },
{ "id": 2, "name": "common => Germany, official => \"Federal Republic of Germany\", native => Deutschland" }
]
.. code-tab:: bash Curl
curl "http://localhost:3000/countries" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
[
{ "id": 1, "name": "common => Egypt, official => \"Arab Republic of Egypt\", native => مصر" },
{ "id": 2, "name": "common => Germany, official => \"Federal Republic of Germany\", native => Deutschland" }
]
EOF
Notice that the use of ``"`` in the value of the ``name`` column needs to be escaped using a backslash ``\``.
You can also query and filter the value of a ``hstore`` column using the arrow operators, as you would do for a :ref:`JSON column<json_columns>`. For example, if you want to get the native name of Egypt, the query would be:
.. tabs::
.. code-tab:: http
GET /countries?select=name->>native&name->>common=like.Egypt HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/countries?select=name->>native&name->>common=like.Egypt"
.. code-block:: json
[{ "native": "مصر" }]
PostGIS
------------------
You can use the string representation for `PostGIS <https://postgis.net/>`_ data types such as ``geometry`` or ``geography``. As an example, let's create a table using the ``geometry`` type (you need to `install PostGIS <https://postgis.net/install/>`_ first).
.. code-block:: postgres
-- Activate the postgis module in the current database
create extension if not exists postgis;
create table coverage (
id int primary key,
name text unique,
area geometry
);
Say you want to add areas in polygon format. The request using string representation would look like:
.. tabs::
.. code-tab:: http
POST /coverage HTTP/1.1
Content-Type: application/json
[
{ "id": 1, "name": "small", "area": "SRID=4326;POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))" },
{ "id": 2, "name": "big", "area": "SRID=4326;POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))" }
]
.. code-tab:: bash Curl
curl "http://localhost:3000/coverage" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
[
{ "id": 1, "name": "small", "area": "SRID=4326;POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))" },
{ "id": 2, "name": "big", "area": "SRID=4326;POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))" }
]
EOF
Now, when you request the information, PostgREST will automatically cast the ``area`` column to ``JSON`` format. Although this output is useful, you will want to use the PostGIS functions to have more control on filters or casts. For these cases, creating a ``view`` is your best option. For example, let's use some of the functions to get the data in `GeoJSON format <https://geojson.org/>`_ and to calculate the area in square units:
.. code-block:: postgres
create or replace view coverage_geo as
select name,
-- Get the Geometry Object
st_AsGeoJSON(c.area)::json as geo_geometry,
-- Get the Feature Object
st_AsGeoJSON(c.*)::json as geo_feature,
-- Calculate the area in square units
st_area(c.area) as square_units
from coverage c;
-- Create another view for the FeatureCollection Object
-- for the sake of making the examples clearer
create or replace view coverage_geo_collection as
select
json_build_object(
'type', 'FeatureCollection',
'features', json_agg(st_AsGeoJSON(c.*)::json)
)
as geo_feature_collection
from coverage c;
Now the query will return the information as you expected:
.. tabs::
.. code-tab:: http
GET /coverage_geo?name=eq.big HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/coverage_geo?name=eq.big"
.. code-block:: json
[
{
"name": "big",
"geo_geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[10,0],[10,10],[0,10],[0,0]]
]
},
"geo_feature": {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[10,0],[10,10],[0,10],[0,0]]
]
},
"properties": {
"id": 2,
"name": "big"
}
},
"square_units": 100
}
]
And for the Feature Collection format:
.. tabs::
.. code-tab:: http
GET /coverage_geo_collection HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/coverage_geo_collection"
.. code-block:: json
[
{
"geo_feature_collection": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[1,0],[1,1],[0,1],[0,0]]
]
},
"properties": {
"id": 1,
"name": "small"
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[10,0],[10,10],[0,10],[0,0]]
]
},
"properties": {
"id": 2,
"name": "big"
}
}
]
}
}
]