echo '{"title":"JQ Select"}' | jq '.title | length'
Here are some more examples:
.title | length
will return the length of the title
.number | tostring
will return the issue number as a string
.[] | .key
will return the values of key key
in the array (this is equivalent to this .[].key
)
This means that sorting my labels array is simple. I can just change .labels
to .labels | sort
:
"title": "Bump jinja2 from 2.10 to 2.11.3 in /docs",
"number": 2289,
"labels": [
"dependencies",
"feature request"
And if you want just a label count that is easy as well:
"title": "Bump jinja2 from 2.10 to 2.11.3 in /docs",
"number": 2289,
"labels": 2
What I Learned: Pipes and Filters
Everything in jq
is a filter that you can combine with pipes (|
). This mimics the behavior of a UNIX shell.
You can use the pipes and the jq
built-ins to build complicated transformations from simple operations.
It ends up looking something like this:
Maps and Selects Using JQ
The issues list I was looking at has many low-quality issues in it. Let’s say I want to grab all the items that are labeled. This would let me skip all the drive-by fix-my-problem issues.
Unfortunately, it’s impossible to do this with the GitHub API unless you specify all the possible labels in your query. However, I can easily do this query on the command line by filtering our results with jq
. However, to do so, I’m going to need a couple more jq
functions.
My query so far looks like this:
The first thing I can do is simplify it using map
.
map(...)
let’s you unwrap an array, apply a filter and then rewrap the results back into an array. You can think of it as a shorthand for [ .[] | ... ]
and it comes up quite a bit in my experience, so it’s worth it committing to memory.
I can combine that with a select statement that looks like this:
select
is a built-in function that takes a boolean expression and only returns elements that match. It’s similar to the WHERE
clause in a SQL statement or array filter in JavaScript.
Like map
, I find select
comes up quite a bit, so while you may have to come back to this article or google it the first few times you need it, with luck, it will start to stick to your memory after that.
Putting this all together looks like this:
"title": "Bump lxml from 4.3.1 to 4.6.3 in /docs",
"number": 2295,
"labels": 1
"title": "Bump pyyaml from 3.13 to 5.4 in /docs",
"number": 2291,
"labels": 1
"title": "Bump jinja2 from 2.10 to 2.11.3 in /docs",
"number": 2289,
"labels": 1
"title": "Debugging help through showing pipeline intermediates. ",
"number": 2206,
"labels": 1
This uses three object indexes, two maps, two pipes, a length
function, and a select
predicate. But if you’ve followed along, this should all make sense. It’s all just composing together filters until you get the result you need.
Now lets talk about how you can put this knowledge into practice.
In Review
What I Learned
Here is what I’ve learned so far:
jq
lets you select elements by starting with a .
and accessing keys and arrays like it’s a JavaScript Object (which is it is). This feature uses the Object and Array index jq
creates of a JSON document and look like this:
jq
programs can contain object constructors { ... }
and array constructors [ ... ]
. You use these when you want to wrap back up something you’ve pulled out of a JSON document using the above indexes:
jq
contains built-in functions (length
,sort
,select
,map
) and pipes (|
), and you can compose these together just like you can combine pipes and filters at the command line:
Next Steps for Mastering jq
Reading about (or writing about) a tool is not enough to master it. Action is needed. Here is my process for cementing this knowledge:
1. Complete the jq
Tutorial
jq-tutorial is not a tutorial at all, but a collection of around 20 interactive exercises that test you knowledge of jq
. I’ve found it extremely helpful.
2. Try Using Your Memory First
Whenever I need to extract data or transform a JSON document, I try to do it first without looking anything up. If memory fails me, sometimes jqterm, which has auto-completion, is helpful. Often, I still need to look something up, but science has shown that repeated retrieval yields retention. So over time, my retention should improve.
3. Use It
If you don’t use a tool, you will never master it. So when I have a task that can be solved using jq
, then it is what I use. At least for the next little while, even if there is an easier way to do it. Whether it’s exploring a REST API or looking at docker inspect
results, JSON is everywhere, so opportunities abound.
4. Learn More
Lastly, to deepen my knowledge, I’m learning about recursive descent, declaring variables, and defining functions and advanced features found in the manual. Of course, these things rarely come up, but after writing all this, I’m hooked on this tool.
Doing all this isn’t necessary, but if you follow me in some of these steps, I think using jq
will become second nature.
Conclusion
So far I’ve only covered the basics of jq
. The jq
query language is a full programming language and you can do lots of exciting things with it. You convert from JSON to CSV. You can define you own functions and even find primes with jq
:
However, simple stuff – like selecting elements, filtering by key, or value – is often all you need.
I hope this helps make jq
more approachable and that you no longer have to go to google every time you want to query a JSON document.
Also, if you’re the type of person who’s not afraid to do things on the command line then you might like Earthly:
Earthly makes CI/CD super simple
Fast, repeatable CI/CD with an instantly familiar syntax – like Dockerfile and Makefile had a baby.
Learn More
Feedback?
I’d love to hear your feedback, or if you have any tips of your own. Let me know on twitter:
jq is great for pretty-printing JSON but it does so much more.
I never really mastered it and it was a challenge each time I tried to use it.
So I took some time to learn the basics. Here is what you need to know: 🧵
— Adam Gordon Bell 🤓 (@adamgordonbell) August 24, 2021
alias gwip='git commit -a -m "work in progress - fixup"'
I use this alias all the time and it gives me confidence that I can always get back to my last good state. I almost never end up reverting though, and the commits all get fixup
ed away, so I think it’s more useful psychologically than anything else.
A note for the pedants: automated behavior is stored in your basal ganglia. It feels like it’s in my fingers, but really, these actions just fired at a level below my awareness.
By default, jq
pretty-prints all its output. This means that its output is not character-for-character identical to its input.
It’s possible to use jq filters as keys in the Object constructor as well, but that is outside the scope of this guide.
You also aren’t limited by the built-ins. You can write your own functions as well.
People can’t figure out how to do something with jq
and open an issue. Please don’t do this. GitHub issues aren’t the place to post your random struggles with understanding a tool.
A lot of the credit for the strength of this jq
summary goes to Michael Lynch who is writing a book about writing and provided me extensive feedback on an earlier draft of this article.