How can I export to CSV with condition? - json

cat target.json | jq '.[] | select(.sex | endswith("female")) |#csv'
I tried the code above to output csv with the condition, in which only girls are listed.
"target.json"
[
{
"name": "Mike",
"age": "15",
"sex": "male"
},
{
"name": "Dan",
"age": "10",
"sex": "male"
},
{
"name": "Kasia",
"age": "5",
"sex": "female"
}
]
However it fails to create and says this error code.
jq: error (at <stdin>:0): object ({"sex":"...) cannot be csv-formatted, only array
Can anyone show me how?

The following makes no assumptions about the ordering of keys within objects. It also produces a CSV header line, and ensures the output conforms with the typical CSV requirement that the result be "rectangular":
jq -r '
(.[0]|keys_unsorted) as $keys
| $keys,
(.[]
| select(.sex | endswith("female"))
| [.[ $keys[] ]])
| #csv
' target.json

jq -r '
.[]
| select(.sex | endswith("female"))
| to_entries
| map(.value)
| #csv
' target.json
to_entries to:
[
{
"key": "name",
"value": "Kasia"
},
{
"key": "age",
"value": "5"
},
{
"key": "sex",
"value": "female"
}
]
and map(.value) to:
[
"Kasia",
"5",
"female"
]

Related

Can we use dynamic values in static json file

Am having a json file for application configuration like below.
[
{
"name": "environment",
"value": "prod"
},
{
"name": "deployment_date",
"value": "2022-12-21"
}
]
The variable deployment_date, I want it as dynamic to current UTC date. Can we use any programing language to achieve this? something like getUTCDate().toString() instead "2022-12-21"?
Using jq:
jq '(.[] | select(.name == "deployment_date")).value |= (now | todate)' file.json
Output
[
{
"name": "environment",
"value": "prod"
},
{
"name": "deployment_date",
"value": "2022-12-21T12:46:11Z"
}
]
jq '(.[] | select(.name == "deployment_date")).value |= (now | strflocaltime("%Y-%m-%d"))' file.json
Output
[
{
"name": "environment",
"value": "prod"
},
{
"name": "deployment_date",
"value": "2022-12-21"
}
]

How to make jq to pick name value pairs

Might be more or less the same ask as How to get JQ name/value pair from nested (array?) response?, but that question and example there is way too convoluted than what I'm asking --
Giving the input jason as in https://jqplay.org/s/jyKBnpx9NYX
Pick out all the name/value pair under .QueryString, .Params into the same unnested array
E.g., for an input of
{
"Some": "Random stuff",
"One": {
"QueryString": [
{ "Name": "IsOrdered", "Value": "1" },
{ "Name": "TimeStamp", "Value": "11654116426247" }
]
},
"Two": {
"QueryString": [
{ "Name": "IsOrdered", "Value": "1" },
{ "Name": "TimeStamp", "Value": "11654116426247" }
]
},
"Params": [
{ "Name": "ClassName", "Value": "PRODUCT" },
{ "Name": "ListID", "Value": "Products" },
{ "Name": "Mode ", "Value": "1" },
{ "Name": "Dept" , "Value": "5" },
{ "Name": "HasPrevOrder", "Value": "" }
],
"And": {
"QueryString":[]
},
"More": "like",
"More+": "this"
}
The output would be:
[
{
"Name": "IsOrdered",
"Value": "1"
},
{
"Name": "TimeStamp",
"Value": "11654116426247"
},
{
"Name": "IsOrdered",
"Value": "1"
},
{
"Name": "TimeStamp",
"Value": "11654116426247"
},
{
"Name": "ClassName",
"Value": "PRODUCT"
},
{
"Name": "ListID",
"Value": "Products"
},
...
],
without any empty arrays output ([]), while keep the repeated values in the array.
I tried to remove empty arrays output ([]) by changing the jq expression from
[( .. | objects | ( .QueryString, .Params ) | select( . != null) )]
to
[( .. | objects | ( .QueryString, .Params ) | select( . != null && . != []) )]
but it failed.
And the final output need to be unnested into a single array too.
Bonus Q: Would it be possible to output each name/value pair on one line of their own like the following?
{ "Name": "IsOrdered", "Value": "1" },
{ "Name": "TimeStamp", "Value": "11654116426247" },
{ "Name": "IsOrdered", "Value": "1" },
{ "Name": "TimeStamp", "Value": "11654116426247" },
To get the Name/Value objects, one per line, you could go with:
jq -c '.. | objects | (.QueryString, .Params) | .. | objects | select( .Name and .Value)'
or more cavalierly:
jq -c '.. | objects | select( .Name and .Value)'
The && must be replaced with and. On the result you can use | flatten to convert "array of arrays of objects" into just "array of objects".
Bonus A: Use the -c/--compact-output flag of jq together with | flatten[] instead of just | flatten.
Together:
jq -c '
[
..
| objects
| ( .QueryString, .Params )
| select(. != null and . != [])
]
| flatten[]' input.json
Although this expression can be simplified into .. | objects | .QueryString[]?, .Params[]?
The output is:
{"Name":"ClassName","Value":"PRODUCT"}
{"Name":"ListID","Value":"Products"}
{"Name":"Mode ","Value":"1"}
{"Name":"Dept","Value":"5"}
{"Name":"HasPrevOrder","Value":""}
{"Name":"IsOrdered","Value":"1"}
{"Name":"TimeStamp","Value":"11654116426247"}
{"Name":"IsOrdered","Value":"1"}
{"Name":"TimeStamp","Value":"11654116426247"}

Parse 2 files based on key value and recreate another json file [JQ]

I am new to JQ.
I need to make a json file based on another 2 files.
I am worked with it whole day and stack here. Badly need this.
Here is file 1
{
"name": "foo",
"key": "1",
"id": "x"
}
{
"name": "bar",
"key": "2",
"id": "x"
}
{
"name": "baz",
"key": "3",
"id": "y"
}
file 2
{
"name": "a",
"key": "1"
}
{
"name": "b",
"key": "1"
}
{
"name": "c",
"key": "2"
}
{
"name": "d",
"key": "2"
}
{
"name": "e",
"key": "3"
}
Expected Result:
{
"x": {
"foo": [
"a",
"b"
],
"bar": [
"c",
"d"
]
},
"y": {
"baz": [
"e"
]
}
}
I can do it with python script but I need it with jq.
Thanks in advance.
Use reduce on the first file's items ($i) to successively build up the result object using setpath with fields from the item and values as a matching map on the secondary dictionary file ($d).
jq -s --slurpfile d file2 '
reduce .[] as $i ({}; setpath(
[$i.id, $i.name];
[$d[] | select(.key == $i.key).name]
))
' file1
For efficiency, the following solution first constructs a "dictionary" based on file2; furthermore, it does so without having to "slurp" it.
< file2 jq -nc --slurpfile file1 file1 '
(reduce inputs as {$name, $key} ({};
.[$key] += [$name])) as $dict
| reduce $file1[] as {$name, $key, $id} ({};
.[$id] += [ {($name): $dict[$key]} ] )
'

Nested Json parsing using jq in bash

I need to parse a json file , I tied bash script with jq and not getting expected output .
Json File :
[
{
"fqdn": "my-created-lb",
"status": "Active",
"members": {
"10.45.78.9:80": {
"dc": "NA",
"state": "enabled",
"port": 80
},
"10.45.78.10:80": {
"dc": "NA",
"state": "enabled",
"port": 80
},
"10.45.78.11:80": {
"dc": "NA",
"state": "enabled",
"port": 80
},
"10.45.78.12:80": {
"dc": "NA",
"state": "enabled",
"port": 80
}
}
}
]
I need output as :
"my-created-lb"
"10.45.78.9:80","enabled"
"10.45.78.10:80","enabled"
"10.45.78.11:80","enabled"
"10.45.78.12:80","enabled"
I tried below jq , but not getting expected output :
jq '.[] | .fqdn,.members,.members[].state'
But I am getting below output :
"my-created-lb"
{
"10.45.78.9:80": {
"dc": "NA",
"state": "enabled",
"port": 80
},
"10.45.78.10:80": {
"dc": "NA",
"state": "enabled",
"port": 80
},
"10.45.78.11:80": {
"dc": "NA",
"state": "enabled",
"port": 80
},
"10.45.78.12:80": {
"dc": "NA",
"state": "enabled",
"port": 80
}
}
"enabled"
"enabled"
"enabled"
"enabled"
Because you want the key's name, you could use to_entries like this:
jq -r '.[] | .fqdn, ( .members | to_entries | .[] | [ .key, .value.state ] | #tsv )'
Output:
my-created-lb
10.45.78.9:80 enabled
10.45.78.10:80 enabled
10.45.78.11:80 enabled
10.45.78.12:80 enabled
Edit
To get the exact output listed in the original post, modify the jq script to be:
jq -r '.[] | [.fqdn], ( .members | to_entries | .[] | [ .key, .value.state ] ) | #csv'
Output:
"my-created-lb"
"10.45.78.9:80","enabled"
"10.45.78.10:80","enabled"
"10.45.78.11:80","enabled"
"10.45.78.12:80","enabled"
To get precisely your desired output:
jq -r '.[] | ([.fqdn]|#csv), (.members | keys[] as $k | [$k, .[$k].state] | #csv)' file.json
"my-created-lb"
"10.45.78.10:80","enabled"
"10.45.78.11:80","enabled"
"10.45.78.12:80","enabled"
"10.45.78.9:80","enabled"

how to parse json with various arrays

I have a json file that looks like:
[
{
"id": "aaa",
"idMembers": [
"David",
"Mary"
],
"actions": [
{
"id": "1",
"date": "2019-08-28"
},
{
"id": "2",
"date": "2019-08-29"
},
{
"id": "3",
"date": "2019-08-30"
}
]
},
{
"id": "bbb",
"idMembers": [
"Mar",
"Alex"
],
"actions": [
{
"id": "1",
"date": "2019-07-28"
},
{
"id": "2",
"date": "2019-07-29"
}
]
}
]
I would like to obtain a result like:
["David", "Mary", "1", "2019-08-28"]
["David", "Mary", "2", "2019-08-29"]
["David", "Mary", "3", "2019-08-30"]
["Mar", "Alex", "1", "2019-07-28"]
["Mar", "Alex", "2", "2019-07-29"]
I tried:
jq -c '.[] | [ .idMembers[], .actions[].id, .actions[].date] '
But results are:
["David", "Mary", "1", "2", "3", "2019-08-28", "2019-08-29", "2019-08-30"]
["Mar", "Alex", "1", "2", "2019-07-28", "2019-07-29"]
I would like do someting like:
jq -c '.[] | .idMembers[], .actions[] | [ .id, .date] '
but it return me
jq: error (at :1268): Cannot index string with string "id"
Is possible to do something similar to this?
jq -c '.[] | .actions[] | [.idMembers[], .id, .date] '
Make an array out of each object under actions and add it to idMembers.
.[] | .idMembers + (.actions[] | map(.))
map(.) can also be written as [.[]]. For clarification, above is the same as:
.[] | .idMembers + (.actions[0] | map(.)),
.idMembers + (.actions[1] | map(.)),
.idMembers + (.actions[2] | map(.)),
...
.idMembers + (.actions[n] | map(.))
where n is the number of elements in actions.