Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add new element to existing JSON array with jq

Tags:

json

arrays

bash

jq

I want to append an element to an array in a JSON file using the jq``add command, but it's not working.

report-2017-01-07.json file:

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

I am using this command:

$ cat report-2017-01-07.json  | jq -s '.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"}' jq: error: syntax error, unexpected '{', expecting $end (Unix shell quoting issues?) at <top-level>, line 1: .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"}                jq: 1 compile error 

Here's how I want the output to look:

{     "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": "OKKKKKKK",             "message": "metadata loaded into iRODS successfullyyyyy"         }]     } } 
like image 427
Felipe Avatar asked Feb 15 '17 09:02

Felipe


People also ask

Does jq use JSONPath?

jp is a JSON processor for the command line using JSONPath (aka "a simpler jq, and with JSONPath").

Can jq validate JSON?

jq – a lightweight and flexible CLI processor – can be used as a standalone tool to parse and validate JSON data.

How do you pass variables in jq?

Using JSON Variables in jq If you want to use variables that reference JSON objects, this can be done with the --argsjson option. Using --argjson var object will set the variable $var to object . In the example below we set the $location variable to a JSON object, and nest this object into our results.

What is jq in curl?

jq is a program described as “ sed for JSON data": You can use it to slice and filter and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text.


2 Answers

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.

like image 132
Inian Avatar answered Sep 21 '22 19:09

Inian


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 |= [ _ ] + . 
like image 20
peak Avatar answered Sep 18 '22 19:09

peak