Everything in jq 133,477 is a filter: it takes one input and produces zero or more outputs. The identity . passes its input through, which is why jq . pretty-prints. .books and .[0] pick a member and an element, .[] emits each element separately, | feeds every output of the left filter into the right one, and , runs two filters on the same input. select(cond) passes its input only when the condition is true, // supplies a default for null or false, and -r prints strings without quotes.

jq '.books | length' data/books.json
jq -r '.books[] | select(.price < 20) | "\(.id) \(.title) $\(.price)"' data/books.json
jq -c '.books[0] | {title, price, isbn: (.isbn // "n/a")}' data/books.json
jq -c '[.books[] | .genre] | sort, length' data/books.json6
1 The Quiet Harbor $14.99
4 Small Steps to Big Summits $18.75
5 The Clockmaker's Paradox $16.2
{"title":"The Quiet Harbor","price":14.99,"isbn":"n/a"}
["Cooking","Fiction","Home and Garden","Science Fiction","Technology","Travel"]
6Wrapping a filter in [...] collects its outputs into one array, the inverse of .[]. The last line shows the comma: sort, length produced two results from one input. Quote jq programs in single quotes so the shell leaves $, | and " alone.