Why do we need a JSON Query Parser
We developers deal with JSON objects everyday no matter what side of the application you are working on. And the ability to quickly query a complex json structure is a valuable skill to have jq is a tool that helps you to do exactly that.
What is Jq
jq is a lightweight command-line JSON processor. It’s expression language is designed for transforming JSON data through a pipeline of filters. Each filter takes an input and produces an output. Key Properties
- Immutable: Input JSON is never modified; all operations produce new values
- Functional: Based on composable functions and filters
- Stream-based: Each filter processes takes the input stream and produces an output stream which then can be piped just like how unix pipes.
- Zero-Based: Array indexing starts at 0
Basics Usage of Jq
jq-blog on master [?]
❯ jq 'keys' ./main.json
[
"appState",
"elements",
"files",
"source",
"type",
"version"
]
jq-blog on master [?]
❯ jq '.type' ./main.json
"excalidraw"
jq-blog on master [?]
❯ jq '.version' ./main.json
2
We start with the basic one to list all the keys of json use key
jq 'keys' ./.json
keys will retrieve the list of keys of the json file, to filter only one specific key you can use .{key_name}. Jq syntax is flexible and immutable as each function returns a object that can be manipulated in upcoming function Example
Arrays
[
{
"one": 1
},
{
"two": 2
},
{
"three": 3
},
{
"four": 4
},
{
"five": 5
},
{
"six": 6
},
{
"seven": 7
}
]
finding
command | example | output |
---|---|---|
first | jq 'first | { one: 1} |
last | jq 'last' | { seven: 7 } |
nth | jq 'nth(4) | { five: 5 } |
sub-array | jq .[1:2] | [{ one: 1}] |
by Index | jq .[3] | { “four”: 4} |
Array Transformations
Jq transformations are very useful when you want to manipulate arrays.
echo '[1, 2, 2, 3]' | jq '[.[] | . * 2] | unique'
# Output: [2, 4, 6]
Here is a Typescript
equivalent of jq
code
const a = [1, 2, 3, 4, 5, 2];
const b = [...a].map((e) => e * 2); // [.[] | . *2]
const c = b.reduce((values: number[], acc) => { // | unique
if (!values.includes(acc)) {
values.push(acc);
}
return values;
}, []);
- Maps each array element (
.[] | . * 2
). - Collects results into an array (
[...]
). - Filters unique values (
unique
).
Objects
.obj_key | [ .[] | . ] | first
The above jq
query will iterate a json object and convert it into a array and return its first item in it. Like javascript you can get only the keys of
the specific object by using the keys
query similiarly values
will return the values only which also can be converted into an array for
later transformations.
.block | values | map(.) | first
if you just want to list all the keys for the particular key in that object you can use the keys
.block | keys | first
Transforming objects
{
"elements": [
{
"type": "line",
"version": 1590,
"versionNonce": 1831758985,
"isDeleted": false,
"id": "eJgo4I1DZ-w3jvmtemDpn"
},
{
"type": "circle",
"version": 1590,
"versionNonce": 1831758985,
"isDeleted": true,
"id": "eJgo4I1DZ-x3jvdmemDpn"
},
{
"type": "square",
"version": 1590,
"versionNonce": 1831758985,
"isDeleted": true,
"id": "eJgo4I1DZ-w3jvmtdslkpn"
}
]
}
Jq command comes with a powerful set of filter which which helps you to filter only the neccessary information and you can combine filters with pipes then you can transform these objects. Eg is a below jq query that filters only the items that have isDeleted property set to true, and you can make these into a array of objects which is passed to next filter. if you wish you can transform the item in that.
.elements | [ .[] | select(.isDeleted == true) ]
This jq will iterate the filtered array and create a new object(immutable) with the previously filtered result.
.elements | [ .[] | select(.isDeleted == true) ] | .[] | { id: .id, type: .type }
Bonus tips
If you are using jq
then you might want to use jnv
which is a rust wrapper for jq
which helps you to run jq
command interactively. No Need to start from scratch again and again. Check it out.
If you are using warp
and using a same jq query in multiple places then you might want to use warp-workflow
. which is a easiest way to changer particular argument without typing the whole command again and again.