apines
apines

Reputation: 1262

jq: adding nested object to a JSON

I have a json file containing several profiles:

{
  "profile1": {
    "user": "user1",
    "channel": "channel1",
    "hook": "hook1"
  },
  "default": {
    "user": "user1",
    "channel": "channel1",
    "hook": "hook2"
  }
}

I want to use jq to insert another profile, "test", so that the end result will be

{
  "profile1": {
    "user": "user1",
    "channel": "channel1",
    "hook": "hook1"
  },
  "default": {
    "user": "user1",
    "channel": "channel1",
    "hook": "hook2"
  },
  "test": {
    "user": "user3",
    "channel": "channel3",
    "hook": "hook3"
  }
}

Directly in the command line I can do it with:

cat filename | 
    jq  '.+  { "test": { "user": "u3", "channel" : "c3", "hook": "w3" } }'

But when I try it in my bash script:

cat "$CONF_FILE" | 
    jq --arg p "$PROFILE" --arg u "$U" --arg c "$C" --arg w "$WH" \
    '.+ { $p: { "user": $u, "channel": $c, "hook": $w } }' `

I'm getting the following error:

jq: error: syntax error, unexpected ':', expecting '}' (Unix shell quoting issues?) at <top-level>, line 1:
.+ { $p: { "user": $u, "channel": $c, "hook": $w } }
jq: error: syntax error, unexpected '}', expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
.+ { $p: { "user": $u, "channel": $c, "hook": $w } }
jq: 2 compile errors

I've tried surrounding the variable with quotes but then I get just the string $p:

cat "$CONF_FILE" | 
    jq --arg p "$PROFILE" --arg u "$U" --arg c "$C" --arg w "$WH" \
    '.+ { "$p": { "user": $u, "channel": $c, "hook": $w } }' 

result:

{
  "profile1": {
    "user": "user1",
    "channel": "channel1",
    "hook": "hook1"
  },
  "default": {
    "user": "user1",
    "channel": "channel1",
    "hook": "hook2"
  },
  "$p": {
    "user": "user3",
    "channel": "channel3",
    "hook": "hook3"
  }
}



EDIT: I have found what seems a temporary solution, converting the object to an array, editing the value (now the profile name is a value and not a key) and converting the array back to an object:

cat "$CONF_FILE" | 
    jq --arg p "$PROFILE" --arg u "$U" --arg c "$C" --arg w "$WH" \
    'to_entries | .+ [ { "key": $p, "value": { "user": $u, "channel": $c, "hook": $w } } ] | from_entries'

It seems crude, but it works. I am still hoping for a better solution...

Upvotes: 2

Views: 6771

Answers (2)

jq170727
jq170727

Reputation: 14715

Here is a script that demonstrates a solution using env to access variables passed via the environment:

#!/bin/bash

CONF_FILE=data.json

export P=test
export U=user3
export C=channel3
export W=hook3

jq '
    .[env.P] = {
       user:    env.U, 
       channel: env.C, 
       hook:    env.W
    }
' "$CONF_FILE"

If data.json contains the sample data this script should produce the output

{
  "profile1": {
    "user": "user1",
    "channel": "channel1",
    "hook": "hook1"
  },
  "default": {
    "user": "user1",
    "channel": "channel1",
    "hook": "hook2"
  },
  "test": {
    "user": "user3",
    "channel": "channel3",
    "hook": "hook3"
  }
}

Upvotes: 4

user3899165
user3899165

Reputation:

Use parenthesis around dynamic keys:

jq --arg p "$PROFILE" --arg u "$U" --arg c "$C" --arg w "$WH" \
'. + {($p): {"user": $u, "channel": $c, "hook": $w}}' "$CONF_FILE"

Upvotes: 6

Related Questions