You want to run a .context,.score filter on each element of v I think:
$ jq -r '.[] | [.c, .e, .score, (.v[] | .context,.score)] | @csv' file.json
"A","B",0.99,"asdf",0.98,"bcdfd",0.97
This is equivalent to using the builtin map function without assembling the results back into an array.
You want to run a .context,.score filter on each element of v I think:
$ jq -r '.[] | [.c, .e, .score, (.v[] | .context,.score)] | @csv' file.json
"A","B",0.99,"asdf",0.98,"bcdfd",0.97
This is equivalent to using the builtin map function without assembling the results back into an array.
The following creates a JSON-encoded CSV record for each top-level array element, and then extracts and decodes them. For each of the top-level elements, the values of the sub-array is incorporated by "flattening" the array.
jq -r 'map([ .c,.e,.score, (.v|map([.context, .score])) ] | flatten | @csv)[]' file
Given a test document equivalent of the following:
[
{
"c": "A",
"e": "B",
"score": 0.99,
"v": [
{ "context": "asdf", "score": 0.98, "url": "..." },
{ "context": "bcdfd", "score": 0.97, "url": "..." }
]
},
{
"c": "A",
"e": "B",
"score": 0.99,
"v": [
{ "context": "asdf", "score": 0.98, "url": "..." },
{ "context": "asdf", "score": 0.98, "url": "..." },
{ "context": "bcdfd", "score": 0.97, "url": "..." }
]
},
{
"c": "A",
"e": "B",
"score": 0.99,
"v": [
{ "context": "asdf", "score": 0.98, "url": "..." },
{ "context": "asdf", "score": 0.98, "url": "..." },
{ "context": "asdf", "score": 0.98, "url": "..." },
{ "context": "bcdfd", "score": 0.97, "url": "..." }
]
}
]
... we get
"A","B",0.99,"asdf",0.98,"bcdfd",0.97
"A","B",0.99,"asdf",0.98,"asdf",0.98,"bcdfd",0.97
"A","B",0.99,"asdf",0.98,"asdf",0.98,"asdf",0.98,"bcdfd",0.97
One could also reorder the operations so that a single use of the @csv operator gets a set of arrays (rather than repeatedly using @csv on single arrays):
jq -r 'map([ .c,.e,.score, (.v|map([.context, .score])) ] | flatten)[]|@csv' file
How can I use jq to filter only certain fields of the original JSON into an CSV?
Using jq to extract values from column-oriented JSON and format in CSV - Unix & Linux Stack Exchange
json - How to concat multiple fields to same line with jq - Stack Overflow
Using jq to parse and display multiple fields in a json serially - Stack Overflow
Hello, I say this stack overflow anser with a simple jq command to convert a JSON to a csv file, but I need to improve it further.
Say I have the following JSON:
[
{
"name": "foo",
"env": "dev",
"version": "1.24"
},
{
"name": "bar",
"env": "staging",
"version": "1.21"
},
{
"name": "boo",
"env": "prod",
"version": "1.23"
},
{
"name": "far",
"env": "prod",
"version": "1.24"
}
]How does one create the CSV with only the "name" and "version" fields?
My current command is:
jq -r '(map(keys) | add | unique) as $cols | map(.[] | {name, version} as $row | $cols | map($row[.])) as $rows | $cols, $rows[] | @csv'This is not working. Can anyone provide some help?
Thanks!
jq has a filter, @csv, for converting an array to a CSV string. This filter takes into account most of the complexities associated with the CSV format, beginning with commas embedded in fields. (jq 1.5 has a similar filter, @tsv, for generating tab-separated-value files.)
Of course, if the headers and values are all guaranteed to be free of commas and double quotation marks, then there may be no need to use the @csv filter. Otherwise, it would probably be better to use it.
For example, if the 'Company Name' were 'Smith, Smith and Smith', and if the other values were as shown below, invoking jq with the "-r" option would produce valid CSV:
$ jq -r '.data | map(.displayName), map(.value) | @csv' so.json2csv.json
"First Name","Last Name","Position","Company Name","Country"
"John (""Johnnie"")","Doe","Director, Planning and Posterity","Smith, Smith and Smith","Transylvania"
I prefer to make each record a row in my CSV.
jq -r '.data | map([.displayName, .rank, .value] | join(", ")) | join("\n")'
Given the data in the question, this outputs
First Name, 1, VALUE
Last Name, 2, VALUE
Position, 3, VALUE
Company Name, 4, VALUE
Country, 5, VALUE
Use @tsv to generated tab-separated values as output:
Copyjq -r '[.user, .cmd] | @tsv' <yourfile
...emits, given your input file:
Copyalex echo '123'
john echo '456'
alex echo '789'
...though if you're filtering for only your user account, you can just print cmd directly, since the user value is known:
Copyjq -r 'select(.user == "alex") | .cmd'
When you write .user .cmd you are asking for the "cmd" field of the JSON object at .user. To obtain both the .user and .cmd values, you could use the "," operator:
Copy.user, .cmd
The above, however, will produce two lines. There are many options for emitting multiple values on a single line. You might wish to consider using string interpolation; or wrapping the values in square brackets and then using one of @csv, @tsv, or join/1; or using the -j command-line option.
This is all pretty clearly explained in the standard jq documentation (see e.g. https://stackoverflow.com/tags/jq/info), as is the use of select for making a selection.
I recommend using String Interpolation:
jq '.users[] | "\(.first) \(.last)"'
We are piping down the result of .users[] to generate the string ".first .last" using string interpolation. \(foo) syntax is used for string interpolation in jq. So, for the above example, it becomes "Stevie Wonder" (".users[].first .users[].second" working elementwise) and "Michael Jackson".
jq reference: String interpolation
You can use addition to concatenate strings.
Strings are added by being joined into a larger string.
jq '.users[] | .first + " " + .last'
The above works when both first and last are string. If you are extracting different datatypes(number and string), then we need to convert to equivalent types. Referring to solution on this question. For example.
jq '.users[] | .first + " " + (.number|tostring)'
Do it in jq, but see @Kusalananda's answer first
jq -r '.host_components[].HostRoles.host_name | join(",")'
No, that's wrong. This is what you need:
jq -r '.host_components | map(.HostRoles.host_name) | join(",")'
Demo:
jq -r '.host_components | map(.HostRoles.host_name) | join(",")' <<DATA
{"host_components":[
{"HostRoles":{"host_name":"one"}},
{"HostRoles":{"host_name":"two"}},
{"HostRoles":{"host_name":"three"}}
]}
DATA
outputs
one,two,three
paste is the best tool to do this job:
your_command | paste -sd, -