jq:从对象中选择键的子集

时间:2015-04-08 14:52:20

标签: json select key subset jq

给定一个来自数组的键的输入json字符串,返回一个只包含原始对象和输入数组中键的条目的对象。

我有一个解决方案,但我认为它并不优雅({($k):$input[$k]}感觉特别笨重...)而且这是我学习的机会。

jq -n '{"1":"a","2":"b","3":"c"}'   \
    | jq --arg keys '["1","3","4"]' \
    '. as $input 
     | ( $keys | fromjson )
     | map( . as $k
          | $input
          | select(has($k))
          | {($k):$input[$k]}
          )
     | add'

有任何想法如何清理它?

我觉得Extracting selected properties from a nested JSON object with jq是一个很好的起点,但我无法让它发挥作用。

5 个答案:

答案 0 :(得分:8)

您可以使用此过滤器:

with_entries(
    select(
        .key as $k | any($keys | fromjson[]; . == $k)
    )
)

答案 1 :(得分:4)

内部检查解决方案:

jq 'with_entries(select([.key] | inside(["key1", "key2"])))'

答案 2 :(得分:1)

杰夫的回答有一些不必要的低效率,假设使用--argjson keys代替--arg keys,这两个问题都由以下问题解决:

with_entries( select( .key as $k | $keys | index($k) ) )

答案 3 :(得分:1)

内部操作员大部分时间都在工作;但是,我发现内部运算符有副作用,有时它选择了不需要的键,假设输入为{ "key1": val1, "key2": val2, "key12": val12 }并由inside(["key12"])选择,它将同时选择"key1""key12"

如果需要完全匹配,请使用in运算符:这样只会选择.key2.key12

jq 'with_entries(select(.key | in({"key2":1, "key12":1})))'

因为in运算符只检查来自对象的键(或从数组中索引exists?),所以它必须用对象语法编写,所需的键作为键,但值无关紧要;使用in运算符不是一个完美的用于此目的,我希望看到Javascript ES6包含API的反向版本实现为jq builtin

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

jq 'with_entries(select(.key | included(["key2", "key12"])))'

从数组

检查项.keyincluded?

答案 4 :(得分:0)

这是一些额外的澄清

对于输入对象{"key1":1, "key2":2, "key3":3},我想删除不在所需键集["key1","key3","key4"]

中的所有键
 jq -n --argjson desired_keys '["key1","key3","key4"]'  \
       --argjson input '{"key1":1, "key2":2, "key3":3}' \
    ' $input
    | with_entries(
          select(
              .key == ($desired_keys[])
          )
       )'

with_entries{"key1":1, "key2":2, "key3":3}转换为以下键值对数组,并将select语句映射到数组上,然后将生成的数组转换回对象。

这是with_entries语句中的内部对象。

[
  {
    "key": "key1",
    "value": 1
  },
  {
    "key": "key2",
    "value": 2
  },
  {
    "key": "key3",
    "value": 3
  }
]
然后我们可以从这个数组中选择符合我们标准的键。

这就是魔术发生的地方......这里是看看这个命令中间发生了什么。以下命令获取扩展的值数组,并将它们转换为我们可以选择的对象列表。

jq -cn '{"key":"key1","value":1}, {"key":"key2","value":2}, {"key":"key3","value":3}
      | select(.key == ("key1", "key3", "key4"))'

这将产生以下结果

{"key":"key1","value":1}
{"key":"key3","value":3}

with entries命令可能有点棘手,但很容易记住它需要一个过滤器并定义如下

def with_entries(f): to_entries|map(f)|from_entries;

这与

相同
def with_entries(f): [to_entries[] | f] | from_entries;

令人困惑的问题的另一部分是==

右侧的多个匹配项

请考虑以下命令。我们看到输出是所有左手列表和右手列表的外部产生。

jq -cn '1,2,3| . == (1,1,3)'
true
true
false
false
false
false
false
false
true

如果该谓词在select语句中,我们在谓词为真时保留输入。请注意,您也可以在这里复制输入。

jq -cn '1,2,3| select(. == (1,1,3))'
1
1
3