I wanted to take a nested set of JSON objects and import them into a SQLite database using sqlite-utils insert
- but I wanted to "flatten" some of the nested rows.
Example data:
{
"status": "success",
"data": {
"generated": "2021-02-18T20:14:02.288Z",
"sites": [
{
"id": "full_data",
"name": "Moscone Center South (full data)",
"active": true,
"location": {
"address": "747 Howard St, San Francisco, CA 94103",
"url": "https://www.google.com/maps/place/Moscone+Center+South,+747+Howard+St,+San+Francisco,+CA+94103",
"lng": -122.401253,
"lat": 37.78392
},
"info": {
"url": "https://sf.gov/location/moscone-center-south-covid-19-vaccine-site"
},
"booking": {
"url": "https://myturn.ca.gov",
"dropins": false,
"info": null
},
"access": {
"wheelchair": true,
"languages": {
"en": true,
"es": true,
"zh": true,
"fil": false,
"vi": false,
"ru": false
},
"remote_translation": {
"available": false,
"info": null
}
},
"access_mode": {
"walk": true,
"drive": false
},
"open_to": {
"everyone": true,
"text": "Open to the public"
},
"appointments": {
"available": true,
"last_updated": "2021-02-18T20:14:02.288Z"
},
"eligibility": {
"65_and_over": true,
"healthcare_workers": true,
"education_and_childcare": false,
"agriculture_and_food": false,
"emergency_services": false
}
}
]
}
}
I wanted to turn this into an array of non-nested objects, like this:
[
{
"id": "full_data",
"name": "Moscone Center South (full data)",
"active": true,
"location_address": "747 Howard St, San Francisco, CA 94103",
"location_url": "https://www.google.com/maps/place/Moscone+Center+South,+747+Howard+St,+San+Francisco,+CA+94103",
"location_lng": -122.401253,
"location_lat": 37.78392
}
]
Thanks to this StackOverflow answer I found the following jq
fragment:
[leaf_paths as $path | {
"key": $path | join("_"), "value": getpath($path)
}] | from_entries
This fragment transforms a nested JSON object into a flat one with "location_address"
style keys instead.
I like trying these things out in interactive tools - https://www.jqkungfu.com/ is my current favourite, which runs the original jq
in your browser compiled to WebAssembly.
I pasted in the example from above and then used this jq
query to confirm that it works - the .data.sites[] | [ ... ]
pattern here pulls out the ["data"]["sites"]
array and applies the flatten transformation to every item within it:
.data.sites[] | [ [leaf_paths as $path | {"key": $path | join("_"), "value": getpath($path)}] | from_entries ]
It worked!
The final, full recipe I used to pull down the JSON, transform and flatten it and insert it into a SQLite database was this:
curl 'https://vaccination-site-microservice.vercel.app/api/v1/sites' | \
jq .data.sites | jq '
[.[] |
[leaf_paths as $path | {"key": $path | join("_"), "value": getpath($path)}]
| from_entries]
' | \
sqlite-utils insert /tmp/sf.db sites -
Created 2021-03-11T07:54:22-08:00 · Edit