1

Completely stuck with this one.

I've got JSON Like this:

{
  "create_option": "Restore",
  "disk_iops_read_write": 120,
  "disk_mbps_read_write": 25,
  "tags": {
    "Monitor": "No",
    "RSVaultBackup": "2dc504bd"
  }
}

and with the following jq

.|to_entries|map("nfs-0_\(.key)=\"\(.value)\"")|.[]

I've got to this

nfs-0_create_option="Restore"
nfs-0_disk_iops_read_write="120"
nfs-0_disk_mbps_read_write="25"
nfs-0_tags="{"Monitor":"No","RSVaultBackup":"2dc504bd"}"

but the nfs-0_tags line section also needs to be in name=value format. What I want to end up with is this

nfs-0_create_option="Restore"
nfs-0_disk_iops_read_write="120"
nfs-0_disk_mbps_read_write="25"
nfs-0_tags={Monitor="No", VaultBackup="2dc504bd"}

I feel I should be able to recursively apply the map but for the life of me I can't figure out how that might be achieved.

Any ideas?

Thanks :)

EDIT:

Okay I think I'm getting a bit closer now with this

.|.tags |= (to_entries | map("\(.key) = \(.value)"))|to_entries|map ("\(.key) = \(.value)")|.[]

I'm now getting

create_option = Restore
disk_iops_read_write = 120
disk_mbps_read_write = 25
tags = ["Monitor = No","RSVaultBackup = 2dc504bd"]

But I need the tags line in curly braces {} with the key unquoted and the value quoted. Like this

nfs-0_tags={Monitor="No", VaultBackup="2dc504bd"}

EDIT:

I still want the output to look like this

nfs-0_create_option="Restore"
nfs-0_disk_iops_read_write="120"
nfs-0_disk_mbps_read_write="25"
nfs-0_tags={Monitor="No", VaultBackup="2dc504bd"}

after the jq runs

2
  • Do you need to quote the value? In the first 3 lines of your expected output they're quoted while the last one is not. Commented Aug 7, 2020 at 16:03
  • @dibery yep - i've edited the post to reflect I still need the value to be quoted Commented Aug 7, 2020 at 16:10

2 Answers 2

2

Here is a solution that allows arbitrarily deep nesting and illustrates the use of recursive inner functions:

def pairs:
  def q:
    if type == "string" then tojson
    elif type == "number" then "\"\(.)\""
    else . end;
  def ip:
    if type == "object"
    then "{" + (to_entries | map("\(.key)=\(.value|ip)") | join(",")) + "}"
    else q end;
  if type == "object"
  then to_entries[] | ("\(.key)=\(.value | ip)")
  else . end;

pairs
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks - another superb bit of information - I've learned so much from these two answers much more than wading through the docs and stumbling around with my own experiments - Great forum!!
1

In act.jq:

def f:
 if .value|type=="object" then
  "nfs-0_\(.key)={\([.value|to_entries|.[]|"\(.key)=\"\(.value)\""]|join(","))}"
 else
  "nfs-0_\(.key)=\"\(.value)\""
 end;

to_entries|.[]|f

Invocation:

jq -rf act.jq file.json

Use type to check if we should go down. If the type of .value is object then we split it again and then collect the result; otherwise we just interpolate it. You can also write f function inline (i.e., after to_entries|.[]).

1 Comment

That's awesome! - Thank you so much. I'm going to take some time to dissect that but right off the bat sticking it in jqplay it works a treat.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.