如何根据 jq 现有 json 中的值输出带有新键名的 json

How can I output a json with the new key name from the value in an existing json by jq

我有一个现有的 json,其来源如下:

{
  "arg1": "Admin",
  "arg2": 0,
  "data": [
    {
      "arg3": "11",
      "user": "user1",
      "age": 51,
      "arg4": "11"
    },
    {
      "arg3": "22",
      "user": "user2",
      "age": 52,
      "arg4": "22"
    },
    {
      "arg3": "33",
      "user": "user3",
      "age": 53,
      "arg4": "33"
    },
    {
      "arg3": "44",
      "user": "user4",
      "age": 54,
      "arg4": "44"
    }
  ]
}

然后我尝试这个命令:

$ cat tmp.json|jq '.data|.[]|{user,age}'
{
  "user": "user1",
  "age": 51,
}
{
  "user": "user2",
  "age": 52,
}
{
  "user": "user3",
  "age": 53,
}
{
  "user": "user4",
  "age": 54,
}

我期望输出的是:

{
  "department": "Admin",
  "user_age": {
    "user1": "51",
    "user2": "52",
    "user3": "53",
    "user4": "54"
  },
  "year": 2016
}

在jq的手册中,我的要求接近example 23

所以我尝试使用from_entries函数

cat tmp.json|jq '.data|.[]|{user,age}|from_entries'

但出现此错误:

jq: error (at :30): Cannot index string with string "key"

我知道这是因为它的格式不等于条目。

那么,我应该怎么做才能转换成预期的输出?

from_entries 需要一个具有 keyvalue 属性的对象数组。但是,您正在生成具有 userage 属性的单独对象,这是行不通的。首先,您需要确保属性在一个数组中,然后为数组中您想要的每个值设置单独的 key/value 对。

话虽如此,您实际上并不需要使用条目来构建结果,它不是完成这项工作的正确工具。您只想从每个数据对象中提取一些属性并添加到另一个对象,将用户映射到年龄。有很多方法可以实现,我会使用 reduce 来实现。

reduce .data[] as $d ({}; .[$d.user] = $d.age)

要获得最终结果,只需将您需要的部分组合到您需要的对象中即可。我不确定你从哪里得到 2016 年的,我假设它只是硬编码的。

{department: .arg1, user_age: (reduce .data[] as $d ({}; .[$d.user] = $d.age)), year: 2016}

你也可以试试:

cat tmp.json|jq '{department: .arg1, user_age: (.data|map({(.user): .age})|add), year: 2016}'

cat tmp.json|jq '{department: .arg1, user_age: .data|map({(.user): .age})|add, year: 2016}'

因为 Jeff explained, from_entries 期望输入形式

[ {key:xxx, value:yyy} ]

所以Hao的过滤器

.data | .[] | {user,age} | from_entries

需要两个小修改才能生成所需的 user_age 对象:

  • 值必须是 {key,value} 个对象
  • 需要将值收集到数组中

例如

.data | [.[]|{key:user, value:age|tostring}] | from_entries

(我们包括 tostring 因为示例输出中的值是字符串)

但由于 [ .[]| ... ]map(...) 相同,因此可以这样写

.data | map({key:user, value:age|tostring}) | from_entries

这是一个完整的解决方案:

{
  "department": .arg1,
  "user_age": .data | map({key:.user, value:.age|tostring}) | from_entries,
  "year": 2016
}

示例输出

{
  "department": "Admin",
  "user_age": {
    "user1": "51",
    "user2": "52",
    "user3": "53",
    "user4": "54"
  },
  "year": 2016
}