Found the answer:
cat <file>.json | jq -r '.files[] | select(.fileName=="FOO") | .md5'
Answer from Marvin Effing on Stack OverflowVery 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
Using jq, extract fields and subfields from a list of objects, grouping paired subfields for saving to csv - Unix & Linux Stack Exchange
jq: Extract element from object or array of objects
ndjson - How do I select multiple fields in jq? - 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
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
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!
I managed to do this when I was teaching myself JSON and playing with JQ. Now I can't remember how I did this. So any guidance would be of value.
Take the following file: settings.json
{
"Bot_API_Key": "SuperSecretKey",
"Channels": [
{
"Channel_Name": "First Channel",
"Channel_Short": "ch01",
"Channel_ID": 4004841050681
},
{
"Channel_Name": "Second Channel",
"Channel_Short": "ch02",
"Channel_ID": 4004685917007
}
]
}If I use the following:
jq '.Channels[] | contains("ch02")' settings.jsonIt returns:
false true
What I actually need is the index number in the array. In this case it must return 1.
I did achieve this once, a few weeks back, when experimenting, and now I can't repeat the results. Like a fool, I didn't document everything I did.
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"]
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.)