使用 jq 计算缺少键的记录

Count records with missing keys using jq

下面是调用 API:

时返回的示例输出
curl "https://mywebsite.com/api/cars.json&page=1" |  jq '.' 

使用 jq,如何计算缺少 charge 键的记录数?我知道第一段代码将包含 jq '. | length' 但是如何过滤掉包含或不包含某个键值的对象?

如果应用于下面的示例,输出将是 1

{
  "current_page": 1,
  "items": [
    {
      "id": 1,
      "name": "vehicleA",
      "state": "available",
      "charge": 100
    },
    {
      "id": 2,
      "name": "vehicleB",
      "state": "available",
    },
    {
      "id": 3,
      "name": "vehicleB",
      "state": "available",
      "charge": 50
    }
  ]
}

这是一个使用 map and length 的解决方案:

.items | map(select(.charge == null)) | length

Try it online at jqplay.org

这是一个使用 reduce 的更有效的解决方案:

reduce (.items[] | select(.charge == null)) as $i (0;.+=1)

Try it online at jqplay.org

示例 运行(假设 data.json 中的更正 JSON 数据)

$ jq -M 'reduce (.items[] | select(.charge == null)) as $i (0;.+=1)' data.json
1

请注意,假设项目没有 "charge":null 成员,以上每项都采用了一个小的快捷方式。如果某些项目可能有 null 费用,那么 == null 的测试将无法区分这些项目和没有 charge 键的项目。如果这是一个问题,使用 has 的上述过滤器的以下形式更好:

.items | map(select(has("charge")|not)) | length

reduce (.items[] | select(has("charge")|not)) as $i (0;.+=1)

这是一个解决方案,它使用了一个简单但功能强大的实用函数,也许值得您的标准库使用:

def sigma(stream): reduce stream as $s (null; . + $s);

您要使用的过滤器是:

sigma(.items[] | select(has("charge") == false) | 1)

这是非常有效的,因为不需要中间数组,并且不涉及无用的 0 添加。此外,如其他地方所述,使用 has 比对 .charge.

的值做出假设更可靠

启动文件

如果您不打算使用 jq 的模块系统,您可以简单地将上述 sigma 的定义添加到文件 ~/.jq 并像这样调用 jq:

jq 'sigma(.items[] | select(has("charge") == false) | 1)'

更好的是,如果您还将 def count(s): sigma(s|1); 添加到文件中,调用将只是:

jq 'count(.items[] | select(has("charge") | not))'

标准库

例如,如果 ~/.jq/jq/jq.jq 是您的标准库,那么假设 count/1 包含在此文件中,您可以像这样调用 jq:

jq 'include "jq"; count(.items[] | select(has("charge") == false))'