The |= .+ part in the filter adds a new element to the existing array. You can use jq with filter like:

jq '.data.messages[3] |= . + {
      "date": "2010-01-07T19:55:99.999Z", 
      "xml": "xml_samplesheet_2017_01_07_run_09.xml", 
      "status": "OKKK", 
      "message": "metadata loaded into iRODS successfullyyyyy"
}' inputJson

To avoid using the hardcoded length value 3 and dynamically add a new element, use . | length which returns the length, which can be used as the next array index, i.e.,

jq '.data.messages[.data.messages| length] |= . + {
      "date": "2010-01-07T19:55:99.999Z", 
      "xml": "xml_samplesheet_2017_01_07_run_09.xml", 
      "status": "OKKK", 
      "message": "metadata loaded into iRODS successfullyyyyy"
}' inputJson

(or) as per peak's suggestion in the comments, using the += operator alone

jq '.data.messages += [{
     "date": "2010-01-07T19:55:99.999Z",
     "xml": "xml_samplesheet_2017_01_07_run_09.xml", 
     "status": "OKKK", 
     "message": "metadata loaded into iRODS successfullyyyyy"
}]'

which produces the output you need:

{
  "report": "1.0",
  "data": {
    "date": "2010-01-07",
    "messages": [
      {
        "date": "2010-01-07T19:58:42.949Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "OK",
        "message": "metadata loaded into iRODS successfully"
      },
      {
        "date": "2010-01-07T20:22:46.949Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "NOK",
        "message": "metadata duplicated into iRODS"
      },
      {
        "date": "2010-01-07T22:11:55.949Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "NOK",
        "message": "metadata was not validated by XSD schema"
      },
      {
        "date": "2010-01-07T19:55:99.999Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "OKKK",
        "message": "metadata loaded into iRODS successfullyyyyy"
      }
    ]
  }
}

Use jq-play to dry-run your jq-filter and optimize any way you want.

Answer from Inian on Stack Overflow
Top answer
1 of 4
192

The |= .+ part in the filter adds a new element to the existing array. You can use jq with filter like:

jq '.data.messages[3] |= . + {
      "date": "2010-01-07T19:55:99.999Z", 
      "xml": "xml_samplesheet_2017_01_07_run_09.xml", 
      "status": "OKKK", 
      "message": "metadata loaded into iRODS successfullyyyyy"
}' inputJson

To avoid using the hardcoded length value 3 and dynamically add a new element, use . | length which returns the length, which can be used as the next array index, i.e.,

jq '.data.messages[.data.messages| length] |= . + {
      "date": "2010-01-07T19:55:99.999Z", 
      "xml": "xml_samplesheet_2017_01_07_run_09.xml", 
      "status": "OKKK", 
      "message": "metadata loaded into iRODS successfullyyyyy"
}' inputJson

(or) as per peak's suggestion in the comments, using the += operator alone

jq '.data.messages += [{
     "date": "2010-01-07T19:55:99.999Z",
     "xml": "xml_samplesheet_2017_01_07_run_09.xml", 
     "status": "OKKK", 
     "message": "metadata loaded into iRODS successfullyyyyy"
}]'

which produces the output you need:

{
  "report": "1.0",
  "data": {
    "date": "2010-01-07",
    "messages": [
      {
        "date": "2010-01-07T19:58:42.949Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "OK",
        "message": "metadata loaded into iRODS successfully"
      },
      {
        "date": "2010-01-07T20:22:46.949Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "NOK",
        "message": "metadata duplicated into iRODS"
      },
      {
        "date": "2010-01-07T22:11:55.949Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "NOK",
        "message": "metadata was not validated by XSD schema"
      },
      {
        "date": "2010-01-07T19:55:99.999Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "OKKK",
        "message": "metadata loaded into iRODS successfullyyyyy"
      }
    ]
  }
}

Use jq-play to dry-run your jq-filter and optimize any way you want.

2 of 4
79

Rather than using |=, consider using +=:

.data.messages += [{"date": "2010-01-07T19:55:99.999Z",
   "xml": "xml_samplesheet_2017_01_07_run_09.xml",
   "status": "OKKK", "message": "metadata loaded into iRODS successfullyyyyy"}]

Prepend

On the other hand, if (as @NicHuang asked) you want to add the JSON object to the beginning of the array, you could use the pattern:

 .data.messages |= [ _ ] + .
🌐
GitHub
gist.github.com › joar › 776b7d176196592ed5d8
Add a field to an object with JQ · GitHub
echo '{"hello": {"value": "world"}}' | jq '.hello.other_key = "new_val"' Copy link · Copy Markdown · Example for adding an element to an array: $ echo '[ {"data1":"A"}, {"data2":"B"} ]' | jq --arg val True '.[] += {uppercase: $val}' [ { "data1": "A", "uppercase": "True" }, { "data2": "B", "uppercase": "True" } ] Copy link ·
Discussions

jq - add objects from file into json array - Unix & Linux Stack Exchange
I want to add an array with elements and value into an existing json file using jq. More on unix.stackexchange.com
🌐 unix.stackexchange.com
jq append data and keep the rest - Unix & Linux Stack Exchange
The above is what I want to append. If I use jq '.access.allowed_users + [ "test2" ]' it will add a new entry there but the rest of the file is lost so I can't recreate the configuration file again. More on unix.stackexchange.com
🌐 unix.stackexchange.com
bash - Adding object string to array using jq doesn't translate escape characters - Unix & Linux Stack Exchange
This value is the array of values after --args on the command line. The --args option is required to be the last option on the command line, and the list is empty in the command above. If you want to create the object that you add separately: to_add=$( jq -n \ --arg block_id "$block_id" \ --arg ... More on unix.stackexchange.com
🌐 unix.stackexchange.com
Using jq to add/prepend an element to the top of an array - Stack Overflow
I'd like to use jq to add a new element to the top of this array (rather than the bottom). More on stackoverflow.com
🌐 stackoverflow.com
🌐
jq
jqlang.org › manual
jq 1.8 Manual
If you run jq with --slurpfile foo bar, then $foo is available in the program and has an array whose elements correspond to the texts in the file named bar. ... This option reads in the named file and binds its content to the given global variable. If you run jq with --rawfile foo bar, then $foo is available in the program and has a string whose content is set to the text in the file named bar.
🌐
iO Flood
ioflood.com › blog › jq-array
Manipulating JSON Arrays with jq | Example Guide
November 15, 2023 - The commands follow common syntax such as, creating arrays and adding elements with echo '[]' | jq '. +=', indexing with .["indexNumber"], modifying elements with .["indexNumber"] = "New Value" .
🌐
Baeldung
baeldung.com › home › files › file editing › how to add objects into json array using jq
How to Add Objects Into JSON Array Using jq | Baeldung on Linux
March 18, 2024 - $ jq '.posts += [inputs]' blog.json post-1.json post-2.json · Once executed, it produces a JSON with all the posts inside the array:
Top answer
1 of 4
24

jq has a flag for feeding actual JSON contents with its --argjson flag. What you need to do is, store the content of the first JSON file in a variable in jq's context and update it in the second JSON

jq --argjson groupInfo "$(<input.json)" '.[].groups += [$groupInfo]' orig.json

The part "$(<input.json)" is shell re-direction construct to output the contents of the file given and with the argument to --argjson it is stored in the variable groupInfo. Now you add it to the groups array in the actual filter part.

Putting it in another way, the above solution is equivalent of doing this

jq --argjson groupInfo '{"id": 9,"version": 0,"lastUpdTs": 1532371267968,"name": "Training" }' \
   '.[].groups += [$groupInfo]' orig.json
2 of 4
15

This is the exact case that the input function is for:

input and inputs [...] read from the same sources (e.g., stdin, files named on the command-line) as jq itself. These two builtins, and jq’s own reading actions, can be interleaved with each other.

That is, jq reads an object/value in from the file and executes the pipeline on it, and anywhere input appears the next input is read in and is used as the result of the function.

That means you can do:

jq '.[].groups += [input]' orig.json input.json

with exactly the command you've written already, plus input as the value. The input expression will evaluate to the (first) object read from the next file in the argument list, in this case the entire contents of input.json.

If you have multiple items to insert you can use inputs instead with the same meaning. It will apply across a single or multiple files from the command line equally, and [inputs] represents all the file bodies as an array.

It's also possible to interleave things to process multiple orig files, each with one companion file inserted, but separating the outputs would be a hassle.

🌐
how.wtf
how.wtf › add-new-element-to-json-array-with-jq.html
Add new element to JSON array with jq | how.wtf
March 19, 2023 - Adding a new element to an existing JSON array can be completed using jq.
Find elsewhere
🌐
Zendesk Developer Docs
developer.zendesk.com › documentation › integration-services › developer-guide › jq-cheat-sheet
jq cheat sheet | Zendesk Developer Docs
Tip: For an example action using this filter, refer to ZIS action: Converting a number to a string. ... The following expression adds a static property to a list of ids and returns the output as an array of objects.
🌐
Petermekhaeil
petermekhaeil.com › til › jq-append-json
Add an object to existing JSON using jq
# Optional: Create new JSON file `feed.json` with empy array. jq -n '[]' > feed.json # Append an object to the array from `feed.json` # and store the new JSON in `feed.json.tmp` jq \ --arg date "$date" \ --arg title "$title" \ '. += [{"date": $date, "title": $title}]' \ feed.json > feed.json.tmp # Replace temp file with original file.
🌐
CopyProgramming
copyprogramming.com › howto › add-new-element-to-existing-json-array-with-jq
Arrays: Using jq to Append a New Element to an Existing JSON Array
May 31, 2023 - The code I'm using adds the new object at the bottom, as shown in the desired output. To achieve this, you can concatenate arrays by adding the new object to an array and using the concat() method to join it with the rest of the array. Here's an example implementation in JavaScript: ...
🌐
Programming Historian
programminghistorian.org › en › lessons › json-and-jq
Reshaping JSON with jq | Programming Historian
May 24, 2016 - Both of these commands are wrapped in [] which tells jq to collect every result into one single array, which is passed with a | along to: join(";"), which turns that array into one single character string, with semicolon delimiters between multiple tweet ids.
🌐
jq recipes
remysharp.com › drafts › jq-recipes
jq recipes
April 16, 2024 - In this case, running Zeit's now ls | jq --raw-input --slurp to find out how many running instance I have: split("\n")[1:-3] | # split into an array of strings, removing the 1st and last few blank lines map([ split(" ")[] | select(.
Top answer
1 of 2
1

I've found the answer:

jq --arg ITEM "$block" '.+[$ITEM|fromjson]' <<< "$parent"

or

jq --argjson ITEM "$block" '.+[$ITEM]' <<< "$parent"
2 of 2
0

The issue is twofold:

  1. You are handing JSON to jq using --arg, which expects text. This means that jq will JSON-encode the given text into a string. The jq utility has a separate option, --argjson, for when the passed data is a JSON document.

  2. In the most general case, you don't want to inject shell variables into a JSON document without encoding their contents. You do this by passing the variable's data to jq using --arg, or by using some other tool (like jo) which expects non-JSON input and produces JSON output.

  • You also use [] unquoted, which would cause the shell to complain if it has the failglob (or equivalent, like nomatch in zsh) shell option set. The zsh shell has its nomatch shell option set by default.

Your issue would be best solved by using jq to add the data directly to your existing document:

jq \
        --arg block_id "$block_id" \
        --arg block_parent_id "$block_parent_id" \
        --argjson current_index 0 \
        --argjson child_sum 0 \
        --arg block_cidr "" \
        --arg block_size "" \
        --arg child_cidr "" \
        --arg child_size "" \
        '. += [ $ARGS.named | .subnets = $ARGS.positional ]' \
        --args \
        <<<"$parent"

In the above command, I create the object that I add to the exsisting list in $parent by using $ARGS.named for each plain (scalar) key-value pair. The value of $ARGS.named is an object with the keys and values taken from the --arg options and their values. I then add the subnets array by using $ARGS.positional. This value is the array of values after --args on the command line. The --args option is required to be the last option on the command line, and the list is empty in the command above.

If you want to create the object that you add separately:

to_add=$(
jq -n \
        --arg block_id "$block_id" \
        --arg block_parent_id "$block_parent_id" \
        --argjson current_index 0 \
        --argjson child_sum 0 \
        --arg block_cidr "" \
        --arg block_size "" \
        --arg child_cidr "" \
        --arg child_size "" \
        '[ $ARGS.named | .subnets = $ARGS.positional ]' \
        --args
)

jq --argjson block "$to_add" '. += $block' <<<"$parent"
🌐
Stack Overflow
stackoverflow.com › questions › 69760036 › how-do-i-use-jq-to-append-an-array-to-this-json-string
bash - How do I use jq to append an array to this json string? - Stack Overflow
method=1234 arraynew=(hello world) echo $arraynew PAYLOAD=$( jq -Rn \ --arg method $method \ --arg array $arraynew \ '{method: [$method], values: $array}' ) ... Please add your desired output (no description, no images, no links) for that sample input to your question (no comment). ... Please read What should I do when someone answers my question? and apply your feed-back to the answers you got.