首页 > 解决方案 > jq - 返回所有具有匹配条件的子属性的顶级属性键

问题描述

我的 JSON 看起来像:

{
  "foo": {
    "restricted": true
  },
  "bar": {
    "restricted": false
  },
  "baz": { }
}

作为单行:

{"foo":{"restricted":true},"bar":{"restricted":false},"baz":{}}

restricted == false我想返回所有具有或不具有子属性的顶级属性键restricted。对于上面的 JSON 示例,预期的输出是:

"bar"
"baz"

标签: jq

解决方案


我想出了以下表达式:

jq "to_entries[] | select(.value.restricted|not) | .key"

to_entries将顶级对象转换为一个对象数组,每个对象具有一个"key"和一个"value"属性:

[
  {
    "key": "foo135",
    "value": {
      "restricted": true
    }
  },
  {
    "key": "foo246",
    "value": {
      "restricted": false
    }
  },
  {
    "key": "foo345",
    "value": {}
  }
]

[]爆炸这个数组。这样做是为了在下一步过滤单个对象:

{
  "key": "foo135",
  "value": {
    "restricted": true
  }
}
{
  "key": "foo246",
  "value": {
    "restricted": false
  }
}
{
  "key": "foo345",
  "value": {}
}

然后为每个对象应用一个过滤器:select(.value.restricted|not). 要过滤掉子属性为真的属性restricted.value.restricted可以使用单个条件反转|not以选择具有和不具有此属性的对象:restricted == false

{
  "key": "foo246",
  "value": {
    "restricted": false
  }
}
{
  "key": "foo345",
  "value": {}
}

最后"key"选择属性:.key. 这将返回匹配对象的名称(最初是顶级属性键):

"foo246"
"foo345"

请注意,并非严格需要管道|字符select(...) | .key。结果是一样的。

如果需要一个字符串数组作为结果......

[
  "foo246",
  "foo345"
]

...然后可以使用以下表达式:

jq "to_entries | map(select(.value.restricted|not).key)"

如您所见,select()可以使用 inside ofmap()来过滤掉单个元素,甚至可以与属性 filter 结合使用.key

如果你[]在末尾追加 like map(...)[],那么数组会被分解,结果又是一个字符串列表,就像在最初的示例中一样,但使用的方法略有不同。


推荐阅读