Either You have a stringified JSON from somewhere, and You want it to look fancy,
or only some fields from huge JSON are needed - jq
to the rescue.
TLDR: start here jq cheat sheet
As simple as piping stringified JSON to jq
would produce a nicely formatted output in terminal, like:
echo '{"id":1000,"name":"Dmitry","country":"ME","timeZone":"UTC+X","matches":{}}' | jq
{
"id": 1000,
"name": "Dmitry",
"country": "ME",
"timeZone": "UTC+X",
"matches": {}
}
You can continue piping it further to next application or a file, as usually with console applications.
To see real benefits we need to add “query” to jq
. Query is added in single quotes, as jq 'some query'
.
Some of allowed “special” symbols are: {}
for dictionary, []
for an array.
We can get both keys
& values
or only value
we care for. Syntax for both
key
& value
is jq '{key1, key2}'
echo '{"id":1000,"name":"Dmitry","country":"ME","timeZone":"UTC+X","matches":{}}' | jq '{id, name}'
{
"id": 1000,
"name": "Dmitry"
}
and for value
- jq '.key1, key2'
.
echo '{"id":1000,"name":"Dmitry","country":"ME","timeZone":"UTC+X","matches":{}}' | jq '.id, .name'
1000
"Dmitry"
Nested property matches
is an object itself and may contain key-values
. Like here:
{
"id": 1000,
"name": "Dmitry",
"country": "ME",
"timeZone": "UTC+X",
"matches": {
"infoSec": false,
"paySec": [
{
"id": 12
},
{
"id": 998
}
]
}
}
Say we care only for paySec
, the query to get both keys
& values
would be:
jq '.matches | {paySec}'
we piping inside query with |
.
echo '{"id":1000,"name":"Dmitry","country":"ME","timeZone":"UTC+X","matches":{"infoSec":false,"paySec":[{"id":12},{"id":998}]}}' | jq '.matches | {paySec}'
{
"paySec": [
{
"id": 12
},
{
"id": 998
}
]
}
and for values
only:
jq '.matches | .paysec'
echo '{"id":1000,"name":"Dmitry","country":"ME","timeZone":"UTC+X","matches":{"infoSec":false,"paySec":[{"id":12},{"id":998}]}}' | jq '.matches | .paySec'
[
{
"id": 12
},
{
"id": 998
}
]
Real life scenario most likely would require having a user id
from top level and his matches
on paysec
from nested properties, omitting other key-values
.
The tricky part is that we need to make a remap in a query with :
. So the query syntax would be be:
jq '{id, matches: matches | {paysec}}'
echo '{"id":1000,"name":"Dmitry","country":"ME","timeZone":"UTC+X","matches":{"infoSec":false,"paySec":[{"id":12},{"id":998}]}}' | jq '{id, matches: .matches | {paySec}}'
{
"id": 1000,
"matches": {
"paySec": [
{
"id": 12
},
{
"id": 998
}
]
}
}
Once we started remapping, we can flatten is further with by making matches
-> paySecMatches
and skipping the paySec
key.
The query: jq '{id, paySecMatches: .matches | .paySec}'
echo '{"id":1000,"name":"Dmitry","country":"ME","timeZone":"UTC+X","matches":{"infoSec":false,"paySec":[{"id":12},{"id":998}]}}' | jq '{id, paySecMatches: .matches | .paySec}'
{
"id": 1000,
"paySecMatches": [
{
"id": 12
},
{
"id": 998
}
]
}
Need to add []
as an array symbol to a key, to tell jq
we are accessing or creating an array.
To flatten such array { list: [ { id: 1 },{ id: 2 } ] }
into {flatList: [1, 2]}
we do:
jq '{list: [.list[] | .id]}'
, what stands for: “give Me a dictionary, with single property flatList
, that is an array
,
consisting of values from list
array’s values gotten by id
key”.
echo '{"list": [{"id":1},{"id":2}]}' | jq '{flatList:[.list[] | .id]}'
{
"flatList": [
1,
2
]
}
jq
allows even select
type queries and math
, but never had to dive that deep. While the syntax takes time to grasp,
still better than to write javascript
throw-away code.