Count records with missing keys using jq
Here is a solution using map
and length
:
.items | map(select(.charge == null)) | length
Here is a more efficient solution using reduce
:
reduce (.items[] | select(.charge == null)) as $i (0;.+=1)
Sample Run (assuming corrected JSON data in data.json
)
$ jq -M 'reduce (.items[] | select(.charge == null)) as $i (0;.+=1)' data.json1
Note that each of the above takes a minor shortcut assuming that the items won't have a "charge":null
member. If some items could have a null
charge then the test for == null
won't distinguish between those items and items without the charge
key. If this is a concern the following forms of the above filters which use has
are better:
.items | map(select(has("charge")|not)) | lengthreduce (.items[] | select(has("charge")|not)) as $i (0;.+=1)
Here is a solution that uses a simple but powerful utility function worthy perhaps of your standard library:
def sigma(stream): reduce stream as $s (null; . + $s);
The filter you'd use with this would be:
sigma(.items[] | select(has("charge") == false) | 1)
This is very efficient as no intermediate array is required, and no useless additions of 0 are involved. Also, as mentioned elsewhere, using has
is more robust than making assumptions about the value of .charge
.
Startup file
If you have no plans to use jq's module system, you can simply add the above definition of sigma
to the file ~/.jq and invoke jq like so:
jq 'sigma(.items[] | select(has("charge") == false) | 1)'
Better yet, if you also add def count(s): sigma(s|1);
to the file, the invocation would simply be:
jq 'count(.items[] | select(has("charge") | not))'
Standard Library
If for example ~/.jq/jq/jq.jq is your standard library, then assuming count/1
is included in this file, you could invoke jq like so:
jq 'include "jq"; count(.items[] | select(has("charge") == false))'