Encode JSON value while disabling line wrapping - json
I originally had an issue with a JSON (let's call it "raw_data.json") that looked like this:
[
{
"metadata": {
"project": [
"someProject1",
"someProject2"
],
"table_name": [
"someTable1",
"someTable2"
],
"sys_insertdatetime": "someDate",
"sys_sourcesystem": "someSourceSystem"
},
"data": {
"field1": 63533712,
"field2": "",
"field3": "hello",
"field4": "other",
"field5": 2022,
"field6": "0",
"field7": "0",
"field8": "0",
"field9": "0",
"field10": "0",
"field11": "0"
}
},
{
"metadata": {
"project": [
"someProject1",
"someProject2"
],
"table_name": [
"someTable1",
"someTable2"
],
"sys_insertdatetime": "someDate",
"sys_sourcesystem": "someSourceSystem"
},
"data": {
"field1": 63533713,
"field2": "Y2JjLTIwMjItdzA1LXRyZi1vZmZyZXMtcmVuZm9ydC1jaGVxdWllci13MDU=",
"field3": "A0AVB",
"field4": "other",
"field5": "HJlbmZvcnQgY2hlcXVpZXIgVzA1",
"field6": "",
"field7": "02/02/2022",
"field8": "14/02/2022",
"field9": "Ticket"
}
}
]
The dictionaries were pretty big and usually spanned over several lines on my monitor. That was an issue because I needed to encode the whole thing in Base64 and send the result with a HTTP POST method. But the encoding tended to wrap lines by adding newlines characters, which caused my POST method to fail.
I fortunately found a question with the following solution:
export DATA=$(cat 'raw_data.json')
export ENCODED_DATA=$(echo "$DATA" | jq -c . | base64 -w 0)
Problem is, my JSON has now changed to this:
{
"request_id": 1234,
"data_to_be_encoded": [
{
"metadata": {
"project": [
"someProject1",
"someProject2"
],
"table_name": [
"someTable1",
"someTable2"
],
"sys_insertdatetime": "someDate",
"sys_sourcesystem": "someSourceSystem"
},
"data": {
"field1": 63533712,
"field2": "",
"field3": "hello",
"field4": "other",
"field5": 2022,
"field6": "0",
"field7": "0",
"field8": "0",
"field9": "0",
"field10": "0",
"field11": "0"
}
},
{
"metadata": {
"project": [
"someProject1",
"someProject2"
],
"table_name": [
"someTable1",
"someTable2"
],
"sys_insertdatetime": "someDate",
"sys_sourcesystem": "someSourceSystem"
},
"data": {
"field1": 63533713,
"field2": "Y2JjLTIwMjItdzA1LXRyZi1vZmZyZXMtcmVuZm9ydC1jaGVxdWllci13MDU=",
"field3": "A0AVB",
"field4": "other",
"field5": "HJlbmZvcnQgY2hlcXVpZXIgVzA1",
"field6": "",
"field7": "02/02/2022",
"field8": "14/02/2022",
"field9": "Ticket"
}
}
]
}
Basically I needed to keep the request_id key-value pair as is, while what was inside the data_to_be_encoded key had to be encoded. Again, another post offered a nice solution:
export DATA=$(cat 'raw_data.json')
export ENCODED_DATA=$(echo "$DATA" | jq '.data_to_be_encoded |= #base64')
Except for the fact that this solution adds line wrapping and I haven't found a way to disable that feature like I managed to do with the first solution.
I did try this:
export ENCODED_DATA=$(echo "$DATA" | jq -c .data_to_be_encoded | base64 -w 0)
But it only returns the value inside the data_to_be_encoded key and not the whole JSON. So I'm back to square one.
How can I get the best of both worlds? In other words, how can I disable the line wrapping while at the same time encoding a specific part of my JSON?
Use jq's #base64 builtin, rather than doing the conversion outside because that way you can either convert all or nothing.
jq '.data_to_be_encoded |= #base64'
{
"request_id": 1234,
"data_to_be_encoded": "W3sibWV0YWRhdGEiOnsicHJvamVjdCI6WyJzb21lUHJvamVjdDEiLCJzb21lUHJvamVjdDIiXSwidGFibGVfbmFtZSI6WyJzb21lVGFibGUxIiwic29tZVRhYmxlMiJdLCJzeXNfaW5zZXJ0ZGF0ZXRpbWUiOiJzb21lRGF0ZSIsInN5c19zb3VyY2VzeXN0ZW0iOiJzb21lU291cmNlU3lzdGVtIn0sImRhdGEiOnsiZmllbGQxIjo2MzUzMzcxMiwiZmllbGQyIjoiIiwiZmllbGQzIjoiaGVsbG8iLCJmaWVsZDQiOiJvdGhlciIsImZpZWxkNSI6MjAyMiwiZmllbGQ2IjoiMCIsImZpZWxkNyI6IjAiLCJmaWVsZDgiOiIwIiwiZmllbGQ5IjoiMCIsImZpZWxkMTAiOiIwIiwiZmllbGQxMSI6IjAifX0seyJtZXRhZGF0YSI6eyJwcm9qZWN0IjpbInNvbWVQcm9qZWN0MSIsInNvbWVQcm9qZWN0MiJdLCJ0YWJsZV9uYW1lIjpbInNvbWVUYWJsZTEiLCJzb21lVGFibGUyIl0sInN5c19pbnNlcnRkYXRldGltZSI6InNvbWVEYXRlIiwic3lzX3NvdXJjZXN5c3RlbSI6InNvbWVTb3VyY2VTeXN0ZW0ifSwiZGF0YSI6eyJmaWVsZDEiOjYzNTMzNzEzLCJmaWVsZDIiOiJZMkpqTFRJd01qSXRkekExTFhSeVppMXZabVp5WlhNdGNtVnVabTl5ZEMxamFHVnhkV2xsY2kxM01EVT0iLCJmaWVsZDMiOiJBMEFWQiIsImZpZWxkNCI6Im90aGVyIiwiZmllbGQ1IjoiSEpsYm1admNuUWdZMmhsY1hWcFpYSWdWekExIiwiZmllbGQ2IjoiIiwiZmllbGQ3IjoiMDIvMDIvMjAyMiIsImZpZWxkOCI6IjE0LzAyLzIwMjIiLCJmaWVsZDkiOiJUaWNrZXQifX1d"
}
Demo
If you need all in one line, use the -c option as before:
jq -c '.data_to_be_encoded |= #base64'
{"request_id":1234,"data_to_be_encoded":"W3sibWV0YWRhdGEiOnsicHJvamVjdCI6WyJzb21lUHJvamVjdDEiLCJzb21lUHJvamVjdDIiXSwidGFibGVfbmFtZSI6WyJzb21lVGFibGUxIiwic29tZVRhYmxlMiJdLCJzeXNfaW5zZXJ0ZGF0ZXRpbWUiOiJzb21lRGF0ZSIsInN5c19zb3VyY2VzeXN0ZW0iOiJzb21lU291cmNlU3lzdGVtIn0sImRhdGEiOnsiZmllbGQxIjo2MzUzMzcxMiwiZmllbGQyIjoiIiwiZmllbGQzIjoiaGVsbG8iLCJmaWVsZDQiOiJvdGhlciIsImZpZWxkNSI6MjAyMiwiZmllbGQ2IjoiMCIsImZpZWxkNyI6IjAiLCJmaWVsZDgiOiIwIiwiZmllbGQ5IjoiMCIsImZpZWxkMTAiOiIwIiwiZmllbGQxMSI6IjAifX0seyJtZXRhZGF0YSI6eyJwcm9qZWN0IjpbInNvbWVQcm9qZWN0MSIsInNvbWVQcm9qZWN0MiJdLCJ0YWJsZV9uYW1lIjpbInNvbWVUYWJsZTEiLCJzb21lVGFibGUyIl0sInN5c19pbnNlcnRkYXRldGltZSI6InNvbWVEYXRlIiwic3lzX3NvdXJjZXN5c3RlbSI6InNvbWVTb3VyY2VTeXN0ZW0ifSwiZGF0YSI6eyJmaWVsZDEiOjYzNTMzNzEzLCJmaWVsZDIiOiJZMkpqTFRJd01qSXRkekExTFhSeVppMXZabVp5WlhNdGNtVnVabTl5ZEMxamFHVnhkV2xsY2kxM01EVT0iLCJmaWVsZDMiOiJBMEFWQiIsImZpZWxkNCI6Im90aGVyIiwiZmllbGQ1IjoiSEpsYm1admNuUWdZMmhsY1hWcFpYSWdWekExIiwiZmllbGQ2IjoiIiwiZmllbGQ3IjoiMDIvMDIvMjAyMiIsImZpZWxkOCI6IjE0LzAyLzIwMjIiLCJmaWVsZDkiOiJUaWNrZXQifX1d"}
Demo
Related
How to filter missing inner key by using jq
Got a json input like this: [ { "dimensions": "helloworld", "metrics": "sum(is_error)", "values": { "timestamp": 1558322460000, "value": "0.0" } }, { "dimensions": "helloworld", "metrics": "sum(is_error)", "values": { "timestamp": 1558322160000, "value": "0.0" } }, { "dimensions": "helloworld", "metrics": "sum(is_error)", "values": "3423.25" } ] The third object doesnot have a timestamp on it. How could I return all the object only have a timestamp on it. Like the following: [ { "dimensions": "helloworld", "metrics": "sum(is_error)", "values": { "timestamp": 1558322460000, "value": "0.0" } }, { "dimensions": "helloworld", "metrics": "sum(is_error)", "values": { "timestamp": 1558322160000, "value": "0.0" } } ] Many thanks in advance. Cheers, Vincent
map( select ( .values | has("timestamp")? ))
and here's an alternative solution, using a walk-path unix tool for JSON: jtc: bash $ <file.json jtc -w'<timestamp>l:[-2]' -j [ { "dimensions": "helloworld", "metrics": "sum(is_error)", "values": { "timestamp": 1558322460000, "value": "0.0" } }, { "dimensions": "helloworld", "metrics": "sum(is_error)", "values": { "timestamp": 1558322160000, "value": "0.0" } } ] bash $ it finds each (all) label timestamp, then goes 2 levels up from the found json entry and prints found Json element. -j wraps all printed walks back into array. PS> Disclosure: I'm the creator of the jtc tool
Working example: [ .[] | select (.values | has("timestamp")?) ] https://jqplay.org/s/n5jsRsPMhW Or alternative: [ .[] | select (.values.timestamp?) ] https://jqplay.org/s/HRWV44YgUp P.S. This one was incorrect because of after .[] you are working with each item separately, not with array. So 'map' function is unnecessary.
Passing JSON value using jq command to a new JSON file
I ran curl command and then parsed the value ("id"). request: curl "http://192.168.22.22/test/index/limit:1/page:1/sort:id/pag1.json" | jq -r '.[0].id' curl response: [ { "id": "381", "org_id": "9", "date": "2018-10-10", "info": "THIS IS TEST", "uuid": "5bbd1b41bc", "published": 1, "an": "2", "attribute_count": "4", "orgc_id": "8", "timestamp": "1", "dEST": "0", "sharing": "0", "proposal": false, "locked": false, "level_id": "1", "publish_timestamp": "0", "disable_correlation": false, "extends_uuid": "", "Org": { "id": "5", "name": "test", "uuid": "5b9bc" }, "Orgc": { "id": "1", "name": "test", "uuid": "5b9f93bdeac1b41bc" }, "ETag": [] } ] jq response: 381 Now I'm trying to get the "id" number 381, and then to create a new JSON file on the disk when I place the "id" number in the right place. The new JSON file for example: { "request": { "Event": { "id": "381", "task": "new" } } }
Given your input, this works: jq -r '{"request": {"Event": {"id": .[0].id, "task": "new"}}}' > file
Add the same element of array in a existing JSON using jq
I have a json file and I want to add some value from top in another place in json. I am trying to use jq command line. { "channel": "mychannel", "videos": [ { "id": "10", "url": "youtube.com" }, { "id": "20", "url": "youtube.com" } ] } The output would be: { "channel": "mychannel", "videos": [ { "channel": "mychannel", "id": "10", "url": "youtube.com" }, { "channel": "mychannel", "id": "20", "url": "youtube.com" } ] } in my json the "channel" is static, same value always. I need a way to concatenate always in each video array. Someone can help me? jq .videos + channel
Use a variable to remember .channel in the later stages of the pipeline. $ jq '.channel as $ch | .videos[].channel = $ch' tmp.json { "channel": "mychannel", "videos": [ { "id": "10", "url": "youtube.com", "channel": "mychannel" }, { "id": "20", "url": "youtube.com", "channel": "mychannel" } ] }
Struggling with parsing JSON with jq
I've read all the posts related to it, I'm playing around with it for hours, and still can't manage to get a grip of this tool which seems to be exactly what I need if I just find a way to make it work as I need... So here's a sample of my JSON: { "res": "0", "main": { "All": [ { "field1": "a", "field2": "aa", "field3": "aaa", "field4": "0", "active": "true", "id": "1" }, { "field1": "b", "field2": "bb", "field3": "bbb", "field4": "0", "active": "false", "id": "2" }, { "field1": "c", "field2": "cc", "field3": "ccc", "field4": "0", "active": "true", "id": "3" }, { "field1": "d", "field2": "dd", "field3": "ddd", "field4": "0", "active": "true", "id": "4" } ] } } I'd like to selectively extract some of the fields and get a csv output like this: field1,field2,field3,id a,aa,aaa,1 b,bb,bbb,2 c,cc,ccc,3 d,dd,ddd,4 Please notice I've skipped some fields and I'm also not interested in the parent arrays and such. Thanks a lot in advance.
First your JSON needs to be fixed as following: { "main": { }, "table": { "All": [ { "field1": "a", "field2": "aa", "field3": "aaa", "field4": "0", "active": "true", "id": "1" }, { "field1": "b", "field2": "bb", "field3": "bbb", "field4": "0", "active": "false", "id": "2" }, { "field1": "c", "field2": "cc", "field3": "ccc", "field4": "0", "active": "true", "id": "3" }, { "field1": "d", "field2": "dd", "field3": "ddd", "field4": "0", "active": "true", "id": "4" } ] }, "res": "0" } Second using jq you can do the following in order to generate the table output using column: { echo Field1 Field2 Field3 ID ; cat data.json | jq -r '.table.All[] | (.field1, .field2, .field3, .id)' | xargs -L4 } | column -t Output: Field1 Field2 Field3 ID a aa aaa 1 b bb bbb 2 c cc ccc 3 d dd ddd 4 Using sed: echo "field1,field2,field3,id" ;cat data.json | jq -r '.table.All[] | (.field1, .field2, .field3, .id)' | xargs -L4 | sed 's/ /,/g' Output: field1,field2,field3,id a,aa,aaa,1 b,bb,bbb,2 c,cc,ccc,3 d,dd,ddd,4 Update: Without using sed or xargs , jq has the ability to format the output as csv like the following: cat data.json | jq -r '.table.All[] | [.field1, .field2, .field3, .id] | #csv' Output: "a","aa","aaa","1" "b","bb","bbb","2" "c","cc","ccc","3" "d","dd","ddd","4" Thanks to chepner as he mentioned in comments the header can be added using jq directly as following: jq -r '(([["field1", "field2", "field3", "id"]]) + [(.table.All[] | [.field1,.field2,.field3,.id])])[]|#csv' data.json Output: "field1","field2","field3","id" "a","aa","aaa","1" "b","bb","bbb","2" "c","cc","ccc","3" "d","dd","ddd","4" This command should work correctly according to the last JSON data you have provided in your question: jq -r '(([["field1", "field2", "field3", "id"]]) + [(.main.All[] | [.field1,.field2,.field3,.id])])[]|#csv' data.json ([["field1", "field2", "field3", "id"]]) : The first part of the command is for the csv header (.main.All[] | [.field1,.field2,.field3,.id])]) : As main is the parent of your JSON then you can choose it using .main which will print the array All then to print the contents of this array you have to add [] to the name of this array and the full command will be .main.All[] which will print multiple dictionries and we can specific the needed keys by piping the out put of .main.All[] to another array with the keys we want as this [.field1,.field2,.field3,.id]
Here's an only-jq solution that only requires specifying the desired keys once, e.g. on the command line: jq -r --argjson f '["field1", "field2", "field3", "id"]' ' $f, (.table.All[] | [getpath( $f[]|[.])]) | #csv' Output: "field1","field2","field3","id" "a","aa","aaa","1" "b","bb","bbb","2" "c","cc","ccc","3" "d","dd","ddd","4" Losing the quotation marks One way to avoid quoting the strings would be to pipe into join(",") (or join(", ")) instead of #csv: field1,field2,field3,id a,aa,aaa,1 b,bb,bbb,2 c,cc,ccc,3 d,dd,ddd,4 Of course, this might be unacceptable if the values contain commas. In general, if avoiding the quotation marks around strings is important, a good option to consider is #tsv.
Filter json file objects into a separate json file with jq
At the moment I'm successfully exporting curl output with JQ into a file with valid json. The comment is as below: jsonValues=<curl command> | jq '.["issues"] | map({key: .key, type: .fields.issuetype.name, typeid: .fields.issuetype.id, status: .fields.status.name, summary: .fields.summary})' > FullClosedIssueList.json; ` You can see that I'm doing two things with this one command: Putting all the results into jsonValues. Exporting to FullClosedIssueList.json. I find that the jsonValues objects are formatted missing [, ] and ,. { "key": "ON-12345", "type": "Bug", "typeid": "1", "status": "Closed", "summary": "Some Bug Title" } { "key": "ON-12346", "type": "Bug", "typeid": "1", "status": "Closed", "summary": "Some Other Bug Title" } Whereas the file output is valid json. [ { "key": "ON-12345", "type": "Bug", "typeid": "1", "status": "Closed", "summary": "Some Bug Title" }, { "key": "ON-12346", "type": "Bug", "typeid": "1", "status": "Closed", "summary": "Some Other Bug Title" } ] What command do I need to add to JQ such that the objects passed to the bash variable are valid json? EDIT: This is the same problem as described here
you need the "map" command in that too, in which the select command should be enclosed: cat FullClosedIssueList.json | jq '.[] | map(select(.typeid=="1"))'