使用jq根据对象中变量的值选择对象

479
{"name": "John", "age": 30, "city": "New York"}

我有以下的 JSON 文件:

{
    "FOO": {
        "name": "Donald",
        "location": "Stockholm"
    },
    "BAR": {
        "name": "Walt",
        "location": "Stockholm"
    },
    "BAZ": {
        "name": "Jack",
        "location": "Whereever"
    }
}

我正在使用jq,并希望获取“location”为“Stockholm”的对象的“name”元素。

我知道可以通过以下方式获取所有名称

cat json | jq .[] | jq ."name"
"Jack"
"Walt"
"Donald"

但是我无法弄清楚如何仅打印特定对象,给定一个子键的值(这里是:"location" : "Stockholm")。

5个回答

680

51
我该如何获取父级 'FOO'、'BAR'、'BAZ'? - spazm
1
我不确定你所说的“parent”是什么意思(你是指“key”吗?)...它只是 jq 'keys' json。如果你指的是过滤后的键,给出了 "FOO" "BAR",请使用这个答案,并使用.key代替[.key, .value.name] - ggorlen
为什么元素之间的逗号没有被保留呢? - Essex Boy

313

获取仅包含名称的数据流:

$ jq '.[] | select(.location=="Stockholm") | .name' json

生成:

"Donald"
"Walt"

要获得一系列相应的(键名,"name"属性)对,请考虑:

$ jq -c 'to_entries[]
        | select (.value.location == "Stockholm")
        | [.key, .value.name]' json

输出:

["FOO","Donald"]
["BAR","Walt"]

1
他想根据位置获取整个对象:“我无法弄清楚如何仅打印特定对象,给定子键的值”。 - Fo.
4
在选择后您不需要管道符号:$ jq '.[] | select(.location=="Stockholm").name' json - Deepak
name 键变量化(使用带有 $1 作为参数的 shell 函数)不起作用:termux-contact-list |jq -r '.[] | select(.name=="$1")|.number'。我像这样调用它 cool_fn Name1。然而,这个可以工作:termux-contact-list |jq -r '.[] | select(.name=="Name1")|.number' - Timo
1
@Fo - 在问题正文中,提问者非常明确:“我想获取对象的“名称”元素”。显然,在问题标题中,提问者使用“对象”一词是泛指。 - peak
有没有一种方法可以将输出进行排序,例如 ["FOO","Donald"] ["BAR","Walt"] 排序为 ["BAR","Walt"] ["FOO","Donald"] - Sandeep Kanabar
显示剩余5条评论

58

我有一个类似的相关问题:如果您想要恢复原始对象格式(带有键名,例如FOO,BAR),该怎么办?

Jq提供了to_entriesfrom_entries,用于在对象和键值对数组之间进行转换,再加上在选择周围使用map即可。

  

这些函数在对象和键值对数组之间进行转换。 如果to_entries传递一个对象,则对于输入中的每个k:v条目,输出数组包括{"key":k,"value":v}。

  

from_entries执行相反的转换,而with_entries(foo)是to_entries | map(foo) | from_entries的简写形式,用于对对象的所有键和值执行某些操作。 from_entries接受key、Key、name、Name、value和Value作为键。

jq15 < json 'to_entries | map(select(.value.location=="Stockholm")) | from_entries'

{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}

通过使用with_entries简写方式,这变为:

jq15 < json 'with_entries(select(.value.location=="Stockholm"))'
{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}

6
使用 with_entries() 时需要记住的一点是,通常在 select 子句中也要使用 .value。这是因为 to_entries 宏将给定的条目转换为 .key.value 对,with_entries 同样如此。 - Jaakko

35

只需在 shell 中尝试全文复制粘贴此代码,您就能理解它。

# pass the multiline string to the jq, use the jq to 
# select the attribute named "card_id" 
# ONLY if its neighbour attribute
# named "card_id_type" has the "card_id_type-01" value.
# jq -r means give me ONLY the value of the jq query no quotes aka raw


cat << EOF | \
    jq -r '.[]| select (.card_id_type == "card_id_type-01")|.card_id'
    [  
     { "card_id": "id-00", "card_id_type": "card_id_type-00"},
     { "card_id": "id-01", "card_id_type": "card_id_type-01"},
     { "card_id": "id-02", "card_id_type": "card_id_type-02"}
    ]
EOF
# this ^^^ MUST start first on the line - no whitespace there !!!
# outputs:
# id-01
使用AWS CLI命令进行操作。
 # list my vpcs or
 # list the values of the tags which names are "Name" 
 aws ec2 describe-vpcs | jq -r '.| .Vpcs[].Tags[]
        |select (.Key == "Name") | .Value'|sort  -nr
请注意,在筛选阶段和选择阶段,您可以在层次结构中上下移动:
 kubectl get services --all-namespaces -o json | jq -r '
 .items[] | select( .metadata.name 
     | contains("my-srch-string")) | 
     { name: .metadata.name, ns: .metadata.namespace 
     , nodePort: .spec.ports[].nodePort
     , port: .spec.ports[].port}
 '

我不明白为什么这个得票最少、未被采纳的评论会排在最前面? - D3l_Gato
2
请检查您的个人设置以排序答案...它可能基于最后修改的时间戳; o) - Yordan Georgiev

1
希望这对其他人有所帮助,我在自己的脚本中使用jq已经有数百次了, 但每次都与在其中使用变量作斗争... 在这种情况下,下面是我唯一能够将数字变量传递给它的方法(即在参数/变量周围加上单引号):
id=26533

cat mydata.json | jq -r --arg id "$id" '.sensor[] |
select(.objid=='$id').probe'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接