Skip to content

Commit 2969dd5

Browse files
committed
sqlite geojson post
1 parent 0382275 commit 2969dd5

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed

source/_posts/generate-geojson.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
---
2+
title: Generating GeoJSON in SQLite
3+
date: 2024-09-08 12:20:25
4+
tags:
5+
- sqlite
6+
- geojson
7+
---
8+
9+
[GeoJSON](https://geojson.org/) is an open standard based on JSON to represent geographic features. It supports points, lines, polygons, and multipart collections of the previous feature types. This post demonstrates ways of leveraging point location data in a SQLite database as latitude and longitude and converting into GeoJSON for usage as a map layer. Given a SQLite **locations** table with the following schema:
10+
11+
```
12+
uuid TEXT
13+
timestamp TEXT
14+
json TEXT
15+
data BLOB
16+
```
17+
and the `data` column has the point location data with accuracy values in json format:
18+
19+
```json
20+
{
21+
"location":
22+
{
23+
"lat": 13.5494602,
24+
"lon": 104.2505927
25+
},
26+
"recorded_at": "2024-09-08T01:33:36.625Z",
27+
"additional":
28+
{
29+
"accuracy": 6.78,
30+
},
31+
}
32+
```
33+
34+
First let's filter out any points with accuracy levels above a certain threshold, e.g. 25M, by using JSON parsing:
35+
36+
```sql
37+
SELECT *
38+
FROM locations
39+
WHERE json_extract(json(data), '$.additional.accuracy') > 25;
40+
```
41+
42+
The `json_extract(json(data), '$.additional.accuracy')` extracts the `accuracy` value from the `additional` object in the JSON data.
43+
44+
Now we want to format the existing JSON data in the `data` column as GeoJSON. We can do this with the following query:
45+
46+
```sql
47+
SELECT
48+
id,
49+
uuid,
50+
timestamp,
51+
json_object(
52+
'type', 'Feature',
53+
'geometry', json_object(
54+
'type', 'Point',
55+
'coordinates', json_array(
56+
json_extract(json(data), '$.location.lon'),
57+
json_extract(json(data), '$.location.lat')
58+
)
59+
),
60+
'properties', json_object(
61+
'id', id,
62+
'uuid', uuid,
63+
'timestamp', timestamp
64+
)
65+
) AS geojson
66+
FROM locations;
67+
```
68+
This creates a GeoJSON feature object for each row which includes a point geometry and properties from the other columns. This results GeoJSON for each row in the table as individual points:
69+
70+
```json
71+
{
72+
"type": "Feature",
73+
"geometry":
74+
{
75+
"type": "Point",
76+
"coordinates":
77+
[
78+
104.2505927,
79+
13.5494602
80+
]
81+
},
82+
"properties":
83+
{
84+
"id": 547,
85+
"uuid": "af801da8-5f2e-42d6-b059-b5f7ce96f30c",
86+
"timestamp": "2024-09-08T01:33:36.625Z"
87+
}
88+
}
89+
```
90+
91+
In order to create single GeoJSON file representing all of the rows in the table we need to use a Common Table Expression (CTE) with a subquery that creates individual GeoJSON feature objects for each point and wrap this in a GeoJSON `FeatureCollection`:
92+
93+
```sql
94+
WITH point_features AS (
95+
SELECT
96+
json_object(
97+
'type', 'Feature',
98+
'geometry', json_object(
99+
'type', 'Point',
100+
'coordinates', json_array(
101+
json_extract(json(data), '$.location.lon'),
102+
json_extract(json(data), '$.location.lat')
103+
)
104+
),
105+
'properties', json_object(
106+
'id', id,
107+
'uuid', uuid,
108+
'timestamp', timestamp
109+
)
110+
) AS feature
111+
FROM locations
112+
)
113+
SELECT json_object(
114+
'type', 'FeatureCollection',
115+
'features', json_group_array(feature)
116+
) AS geojson_collection
117+
FROM point_features;
118+
```
119+
120+
This results in a single row with one column named `geojson_collection` containing a complete GeoJSON `FeatureCollection` object with all rows in the table:
121+
122+
```json
123+
{
124+
"type": "FeatureCollection",
125+
"features":
126+
[
127+
{
128+
"type": "Feature",
129+
"geometry":
130+
{
131+
"type": "Point",
132+
"coordinates":
133+
[
134+
104.2505927,
135+
13.5494602
136+
]
137+
},
138+
"properties":
139+
{
140+
"id": 547,
141+
"uuid": "af801da8-5f2e-42d6-b059-b5f7ce96f30c",
142+
"timestamp": "2024-09-08T01:33:36.625Z"
143+
}
144+
},
145+
]
146+
}
147+
```
148+
149+
Copy the results into Sublime Text and view in a sample web view with [MapPreview](https://gh.jdoneill.com/2020/08/15/mappreview/)

0 commit comments

Comments
 (0)