Topic: tech myref prev next
tech myref > jq
Notes on the jq JSON processor
Sort objects in an array by the ‘path’ attribute.
jq '."/home/james/nas/movies"|=sort_by(.path)'
The input file contains an array of objects. Each object has identical attributes, very much like a table in a relational database. One of these attributes, ‘path’, acts as a primary key. It is useful to convert the array of objects into an object of objects, with the key being the primary key ‘path’, and back again.
Convert an object in which each value is an object, into an array with the object’s keys as the ‘path’ element in each object in the array.
jq '. as $in |
{ "/home/james/nas/movies": [keys[] | $in[.] + { path: . } ] }'
Example;
{
"/home/james/nas/movies/Western/True_Grit_2010.mkv": {
"title": "True Grit",
"watched": false,
"year": 2010,
"comment": ""
}
}
Becomes;
[
{
"title": "True Grit",
"watched": false,
"year": 2010,
"comment": "",
"path": "/home/james/nas/movies/Western/True_Grit_2010.mkv"
}
]
To do the opposite, converting the array back into the object;
jq '."/home/james/nas/movies" | map( { (.path): . } ) | add'
Add together two objects from different files;
jq -s '.[0] as $old | .[1] as $new | $old + $new' < jqt1.json < jqt2.json
It is useful to edit the array form locally, but also pick up any new items
that have been added since the report was generated. To do this, convert both
the ‘old’ (downloaded from the server) and the ‘new’ (edited locally) report
files into the object form, combine them with jq
’s ‘+
’ operator, convert
the object back into array form, and finally sort the array by the primary key,
‘path’.
Combining all of the above filters to achieve this;
cp movies.json movies_local.json
jq -s '
.[0] as $old |
.[1] as $new |
($old."/home/james/nas/movies" | map( { (.path): . } ) | add)
as $old_obj |
($new."/home/james/nas/movies" | map( { (.path): . } ) | add)
as $new_obj |
($old_obj + $new_obj) as $in |
{ "/home/james/nas/movies": (
[($in | keys)[] | $in[.] + { path: . } ] | sort_by(.title)
)}
' < movies_remote.json < movies_local.json > movies.json
jq '[ ."/home/james/nas/movies"[] | select(.watched) ] |
length' < movies.json
251
jq '[ ."/home/james/nas/movies"[] | select(.watched == false) ] |
length' < movies.json
302
An alternative might involve defining a function ‘count
’ to count items in an
array.
jq 'def count(s): reduce s as $i (0; .+1);'