JQ - 按层次结构解析字段

JQ - parsing field by hierarchy

我有非常大的 json 我想使用 jq 从中提取数据总和。

我正在尝试所有可能的方法,但我想我在这里遗漏了一些东西..

我的 Json 子集:

{"main":
  {"0": {"x": {"a":1}, "y": {"number of un-used":{"count":2} , "z":2}},
  "1": {"x": {"a":1}, "y": {"number of un-used":{"count":3} , "z":2}},
  "2": {"x": {"a":1}, "y": {"number of un-used":{"count":4} , "z":2}},
  "3": {"x": {"a":1}, "y": {"no un-used":{"z":3} , "z":2}},
  "4": {"x": {"a":1}, "y": {"no un-used":{"z":3} , "z":2}}},
 "no-main":
  {"0": {"x": {"a":1}, "y": {"number of un-used":{"count":2} , "z":2}},
  "1": {"x": {"a":1}, "y": {"number of un-used":{"count":3} , "z":2}},
  "2": {"x": {"a":1}, "y": {"number of un-used":{"count":4} , "z":2}},
  "3": {"x": {"a":1}, "y": {"no un-used":{"z":3} , "z":2}},
  "4": {"x": {"a":1}, "y": {"no un-used":{"z":3} , "z":2}}}}

我想要 "count" - "number of un-used" 的总和,即 "y".

我最成功的一个是:

cat json | jq '.[] | .[].y | .["number of un-used"] | .count'

但结果包含很多 "null" 因为 "number of un-used" 不在所有 "y" 字典中..

可以解决吗?

您可以将零添加到 null 以获得...零。

jq '.[] | .[].y | ."number of un-used" | .count + 0' < input.json

这会生成您要查找的 count 个值的列表,null 个值显示 0。将它们添加到您的总和中应该不会改变它。

jq 可以在其表达式中进行基本算术运算,但让它在内部计算总和会变得​​稍微复杂一些。虽然您可以定义一个使用 reduce 的函数,但通过向命令行附加一些内容可能更容易对这些值求和,如下所示:

| awk '{n+=}END{print n}'

当然,有无数种方法可以将数字相加,有些方法比其他方法更难懂。

$ { printf '%s+' $(jq '.[] | .[].y | ."number of un-used" | .count + 0' input.json); echo 0; } | bc
18

由于 JSON 非常大,您可能需要一个总体上非常有效的解决方案,因此值得考虑以下内容:

def sigma(s): reduce s as $x (0; .+$x);
sigam(.[].[].y | .["number of un-used"] | .count)

请注意,这也解决了空值问题。为了使解决方案更加稳健,您还可以加入一些 post-fix ?

对于巨大的 JSON,您可能需要一个流式处理解决方案,但这会复杂得多,尽管上述定义仍然适用。

如果 JSON 太大而不适合内存,那么可以使用 jq 的流解析器,如此处所示。

调用

$ jq -n --stream -f program.jq input.json

特别注意“-n”选项。

program.jq

def sigma(s): reduce s as $x (0; .+$x);

sigma(inputs 
      | select(length==2) 
      | select(.[0][-3:] == ["y","number of un-used","count"])
      | .[1] )