简体   繁体   中英

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

I have an existing json which have a from like this:

{
  "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"
    }
  ]
}

Then I try this command:

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

What I expect to output is:

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

In jq's manual, my request is close to example 23 .

So I tried to use from_entries function

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

but get this error:

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

I know this is because of its format not equal an entry.

So, what should I do to convert to the expected output?

from_entries expects an array of objects with key and value properties. You are however generating separate objects with user and age properties which just would not work. First of all, you would need to make sure that the properties are in an array, then have the separate key/value pairs for each of the values you want in the array.

With that said, you don't really need to use entries to build out the result, it's not the right tool for the job. You just want to pull some properties from each of the data objects and add to another object mapping users to ages. There's many ways this can be achieved, I would use reduce to accomplish this.

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

To get your final result, just combine the parts you need into the object you're requiring. I'm not sure where you got that 2016 from, I'm assuming it's just hardcoded.

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

you can also try:

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

or

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

As Jeff explained, from_entries expects input of the form

[ {key:xxx, value:yyy} ]

so Hao 's filter

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

requires two small modifications to generate the desired user_age object:

  • the values must be {key,value} objects
  • the values need to be collected into an array

eg

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

(we include tostring because the values in the example output are strings)

But since [ .[]| ... ] [ .[]| ... ] is the same as map(...) this could be written

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

Here is a complete solution:

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

Sample output

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM