【问题标题】:JQ, how to count depending on conditions?JQ,如何根据条件计算?
【发布时间】:2019-07-04 14:37:06
【问题描述】:

使用 jq,我需要根据两个条件获取数组中的计数:它必须有 status === 'skipped' && ref.includes(version)

[
  {
    "id": 15484,
    "sha": "52606c8da57984d1243f436e5d12e275db29a6e0",
    "ref": "v1.4.15",
    "status": "canceled"
  },
  {
    "id": 15483,
    "sha": "52606c8da57984d1243f436e5d12e275db29a6e0",
    "ref": "v1.4.15",
    "status": "canceled"
  },
  {
    "id": 15482,
    "sha": "1b4ccc1dc17e9b8ddb24550c5566d2be6b03465e",
    "ref": "dev",
    "status": "success"
  },
  {
    "id": 15481,
    "sha": "5b6ec939739c5a1513634f3b58bf96522917571d",
    "ref": "dev",
    "status": "failed"
  },
  {
    "id": 15480,
    "sha": "ec18d46f491a4645c68388df91fc41455b421e71",
    "ref": "dev",
    "status": "failed"
  },
  {
    "id": 15479,
    "sha": "dd83a6d6e58cc5114aed8016341ab3c5b3ebb702",
    "ref": "dev",
    "status": "failed"
  },
  {
    "id": 15478,
    "sha": "18ccaf4bc37bf65470b2c6ddaa69e5b4018354a7",
    "ref": "dev",
    "status": "success"
  },
  {
    "id": 15477,
    "sha": "f90900d733bce2be3d9ba9db25f8b51296bc6f3f",
    "ref": "dev",
    "status": "failed"
  },
  {
    "id": 15476,
    "sha": "3cf0431a161e6c9ca90e8248af7b4ec39c54bfb1",
    "ref": "dev",
    "status": "failed"
  },
  {
    "id": 15285,
    "sha": "d24b46edc75d8f7308dbef37d7b27625ef70c845",
    "ref": "dev",
    "status": "success"
  },
  {
    "id": 15265,
    "sha": "52606c8da57984d1243f436e5d12e275db29a6e0",
    "ref": "v1.4.15",
    "status": "success"
  },
  {
    "id": 15264,
    "sha": "9a15f8d4c950047f88c642abda506110b9b0bbd7",
    "ref": "v1.4.15-static",
    "status": "skipped"
  },
  {
    "id": 15263,
    "sha": "9a15f8d4c950047f88c642abda506110b9b0bbd7",
    "ref": "v1.4.15-static",
    "status": "skipped"
  },
  {
    "id": 15262,
    "sha": "76451d2401001c4c51b9800d3cdf62e4cdcc86ba",
    "ref": "v1.4.15-no-js",
    "status": "skipped"
  },
  {
    "id": 15261,
    "sha": "76451d2401001c4c51b9800d3cdf62e4cdcc86ba",
    "ref": "v1.4.15-no-js",
    "status": "skipped"
  },
  {
    "id": 15260,
    "sha": "515cd1b00062e9cbce05420036f5ecc7a898a4bd",
    "ref": "v1.4.15-cli",
    "status": "skipped"
  },
  {
    "id": 15259,
    "sha": "515cd1b00062e9cbce05420036f5ecc7a898a4bd",
    "ref": "v1.4.15-cli",
    "status": "skipped"
  },
  {
    "id": 15258,
    "sha": "b67acd3082da795f022fafc304d267d3afd6b736",
    "ref": "v1.4.15-node",
    "status": "skipped"
  },
  {
    "id": 15257,
    "sha": "b67acd3082da795f022fafc304d267d3afd6b736",
    "ref": "v1.4.15-node",
    "status": "skipped"
  },
  {
    "id": 15256,
    "sha": "4da4a788a85d82527ea568fed4f03da193842a80",
    "ref": "v1.4.15-bs-redux-saga-router-dom-intl",
    "status": "skipped"
  }
]

我们也喜欢使用环境变量进行查询:

  • status=skipped
  • ref=v1.4.15

这项工作,但没有环境变量选项:

cat test.json | jq '[.[] | select(.status=="skipped") | select(.ref | startswith("v1.4.15"))] | length'

这怎么可能?

答案:

status=skipped; ref=v1.4.15; cat test.json | jq --arg REF "$ref" --arg STATUS "$status" -r '[.[] | select(.status==$STATUS) | select(.ref | startswith($REF))] | length'

【问题讨论】:

  • ref.includes(version) 是什么意思?这看起来不像 jq 语法(我认为三个 = 也是错误的)
  • 你所说的计数是指数组匹配元素的数量吗?

标签: json linux bash debian jq


【解决方案1】:

在将对象列表放入数组后,在过滤器末尾使用length() 函数

jq '[.[] | select(.status == "skipped") | select(.ref | test("1\\.4\\.15"))] | length'

但是仅仅返回对象省略了获取长度的逻辑

jq '[.[] | select(.status == "skipped") | select(.ref | test("1\\.4\\.15"))]'

test() 是一种将正则表达式与 JSON 字符串匹配的更强大的方法。 startswith()endswith() 无法匹配位于中间的字符串。

使用变量,

ref="1\.4\.15"
jq --arg status "$status" --arg ref "$ref" \
    '[.[] | select(.status == $status) | select(.ref | test($ref))]|length' json

【讨论】:

  • 我不能不同意。接受这个积极的反馈并接受答案。
  • 只是评论一下正则表达式的使用,如果你要使用它,你需要确保你对需要转义的字符进行转义。这些句点将匹配任何内容,因此可能包含错误的项目。
【解决方案2】:

通过使用 map(select(...) 或等效方法,您可以使用length,但通常使用通用计数函数更有效,例如:

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

sigma(.[] | select(.status=="skipped" and (.ref | startswith("v1.4.15") )) | 1)

使用 shell 和环境变量

jq 手册中介绍了使用 shell 和环境变量,但简而言之,传递字符串值的一种方法是使用命令行选项 --arg,例如大致如下:

jq --arg status "$status" --arg ref "$ref" -f program.jq test.json

【讨论】:

  • 看起来像 jq 但又像 sigma,它不使用环境变量。
【解决方案3】:

我知道jq 在这里很受欢迎,但我可以推荐xidel 吗?见http://videlibri.sourceforge.net/xidel.html
就像jq 一样,它是一个 JSON 解释器,但除了 JSONiq 之外,您还可以使用 XPath/Xquery 函数来做各种很酷的事情。

这将列出具有 2 个条件的所有对象:

xidel -s test.json -e '$json()[status="skipped" and starts-with(ref,"v1.4.15")]'

要计算它们,只需用 count() 函数将查询括起来:

xidel -s test.json -e 'count($json()[status="skipped" and starts-with(ref,"v1.4.15")])'

这将返回9

带变量:

status=skipped
ref=v1.4.15

xidel -s test.json -e 'count($json()[status="'$status'" and starts-with(ref,"'$ref'")])'

【讨论】:

    【解决方案4】:

    为了完整起见,这将是一个等效的 JSONiq 查询:

    let $a := [
       (: copy-paste the entire array here in plain JSON syntax --
          omitted for the sake of brevity :)
    ]
    return count(
       for $obj in $a[]
       where $obj.status eq "skipped"
             and
             matches($obj.ref, "ˆv")
       return $obj
    )
    

    【讨论】:

      猜你喜欢
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多