Found the answer:
cat <file>.json | jq -r '.files[] | select(.fileName=="FOO") | .md5'
Answer from Marvin Effing on Stack OverflowYou 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
json - jq: how to filter an array of objects based on values in an inner array? - Stack Overflow
json - jq convert an array by selecting to a list using only some values of the objects in the array - Unix & Linux Stack Exchange
json - How to select items in JQ based on value in array - Stack Overflow
ndjson - How do I select multiple fields in jq? - Stack Overflow
Given the following JSON, what is the best way to extract the phone numbers, whether inside an object or an array of objects?
{
"phones": {
"Alex Baker": { "location": "mobile", "number": "+14157459038" },
"Bob Clarke": [
{ "location": "mobile", "number": "+12135637813" },
{ "location": "office", "number": "+13104443200" }
],
"Carl Davies": [
{ "location": "office", "number": "+14083078372" },
{ "location": "lab", "number": "+15102340052" }
],
"Drew Easton": { "location": "office", "number": "+18057459038" }
}
}I'm using the following query, but I wonder if there's a better way to do this:
$ cat phones.json | jq '.phones | to_entries | [ .[].value | objects | .number ] + [ .[].value | arrays | .[].number ]' [ "+14157459038", "+18057459038", "+12135637813", "+13104443200", "+14083078372", "+15102340052" ]
Any suggestions will be appreciated, thanks!
Very close! In your select expression, you have to use a pipe (|) before contains.
This filter produces the expected output.
. - map(select(.Names[] | contains ("data"))) | .[] .Id
The jq Cookbook has an example of the syntax.
Filter objects based on the contents of a key
E.g., I only want objects whose genre key contains "house".
$ json='[{"genre":"deep house"}, {"genre": "progressive house"}, {"genre": "dubstep"}]' $ echo "$json" | jq -c '.[] | select(.genre | contains("house"))' {"genre":"deep house"} {"genre":"progressive house"}
Colin D asks how to preserve the JSON structure of the array, so that the final output is a single JSON array rather than a stream of JSON objects.
The simplest way is to wrap the whole expression in an array constructor:
$ echo "$json" | jq -c '[ .[] | select( .genre | contains("house")) ]'
[{"genre":"deep house"},{"genre":"progressive house"}]
You can also use the map function:
$ echo "$json" | jq -c 'map(select(.genre | contains("house")))'
[{"genre":"deep house"},{"genre":"progressive house"}]
map unpacks the input array, applies the filter to every element, and creates a new array. In other words, map(f) is equivalent to [.[]|f].
Here is another solution which uses any/2
map(select(any(.Names[]; contains("data"))|not)|.Id)[]
with the sample data and the -r option it produces:
cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b
a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19
Found out the answer
jq 'select(.items | index("blue"))'
On Jan 30, 2017, a builtin named IN was added for efficiently testing whether a JSON entity is contained in a stream. It can also be used for efficiently testing membership in an array. In the present case, the relevant usage would be:
select( .items as $items | "blue" | IN($items[]) )
If your jq does not have IN/1, then so long as your jq has first/1, you can use this equivalent definition:
def IN(s): . as $in | first(if (s == $in) then true else empty end) // false;
any/0
Using any/0 here is relatively inefficient, e.g. compared to using any/1:
select( any( .items[]; . == "blue" ))
(In practice, index/1 is usually fast enough, but its implementation currently (jq 1.5 and versions through at least July 2017) is suboptimal.)
Adapted from this post on Processing JSON with jq, you can use the select(bool) like this:
$ jq '.[] | select(.location=="Stockholm")' json
{
"location": "Stockholm",
"name": "Walt"
}
{
"location": "Stockholm",
"name": "Donald"
}
To obtain a stream of just the names:
$ jq '.[] | select(.location=="Stockholm") | .name' json
produces:
"Donald"
"Walt"
To obtain a stream of corresponding (key name, "name" attribute) pairs, consider:
$ jq -c 'to_entries[]
| select (.value.location == "Stockholm")
| [.key, .value.name]' json
Output:
["FOO","Donald"]
["BAR","Walt"]