46

This should be easy enough... I want to rename a few keys (ideally with jq), whatever I do seems to error though. Here is a json example below:

[
 {
  "fruit": "strawberry",
  "veg": "apple",
  "worker": "gardener"
 }
]

I'd like to rename the veg key to fruit2 (or example, whatever is easiest) and also the worker key to job.

I realize this is possible in sed, but I'm trying to get to grips with jq

brian d foy
  • 129,424
  • 31
  • 207
  • 592
keeer
  • 783
  • 1
  • 5
  • 11

5 Answers5

48

Use the following jq approach:

jq '[.[] | .["fruit2"] = .veg | .["job"] = .worker | del(.veg, .worker)]' file

The output:

[
  {
    "fruit": "strawberry",
    "fruit2": "apple",
    "job": "gardener"
  }
]
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
32

The key (:-) is with_entries. E.g., given a single object:

with_entries(if .key == "veg" then .key = "fruit2" else . end)

In your case, since you have an array of objects, you could wrap the above in map( ... ).


Note that if the original JSON object already has a key named "fruit2", then the usual "last-most wins" rule applies, where in this case, "last-most" refers to the array of key-value pairs that is used to determine the final result (as per the def of with_entries).

peak
  • 105,803
  • 17
  • 152
  • 177
  • this one is great ! How do you do with multiple keys ? – Varun Chandak Jun 03 '20 at 08:22
  • 3
    One way is to extend the argument to with_entries, e.g. with_entries( if .... end | if ... end) – peak Jun 03 '20 at 08:51
  • Notice: use target original value while target fields already exists. eg: `echo '{"veg":[1,2,3], "fruit2":["hello"]}' | jq 'with_entries(if .key == "veg" then .key = "fruit2" else . end)'` result: `{ "fruit2": [ "hello" ] }` – eaglewu May 04 '23 at 06:18
0

For anyone looking to manipulate the key with a value from value:

$ echo '{ "foo": {"id": 123}, "bar": {"id":456} }'  | jq 'to_entries | map({key:(.key + "-" +(.value.id|tostring)), value:.value}) | from_entries'

If there is a shorter way to do it (maybe using with_entries), I would be happy to know.

barakbd
  • 988
  • 10
  • 16
0

Here's how to use if-then-else-end with elif to rename multiple keys:

map(with_entries(.key |=
  if . == "fruit"  then "fruit2"
elif . == "worker" then "job"
else . end))

(jqplay example)

Note in the current development branch / upcoming 1.7 release the empty else branch will be optional and could be removed, but it's still required in v1.6.

wjordan
  • 19,770
  • 3
  • 85
  • 98
0
jq '[.[] | { fruit2: .veg, other_key: .other_orig_key }]'

check this example

mohRamadan
  • 571
  • 6
  • 15