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
Using JQ to return the index number where an element in an array has a specific value.
jq select multiple elements from an array - Unix & Linux Stack Exchange
json - jq convert an array by selecting to a list using only some values of the objects in the array - Unix & Linux Stack Exchange
jq: Extract element from object or array of objects
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.
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!
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.)
A slightly different approach from what rowboat took:
jq 'map(select(any(contains("a"))))' file
The innermost test tests each of the strings for the substring a. If any string in a sub-array contains a, that sub-array is selected. The map applies the selection to all sub-arrays in the top-level array.
The result is a top-level array with sub-arrays that contain at least one element that contains the substring a:
[
[
"a",
"b",
"c"
],
[
"abc",
"e",
"f"
]
]
jq '[.[] | select(contains(["a"]))]'
With your input array:
$ jq -c << \\ '[.[] | select(contains(["a"]))]'
[
["a", "b", "c"],
["abc", "e", "f"],
["g", "h", "i"]
]
\
[["a","b","c"],["abc","e","f"]]
man jq (https://stedolan.github.io/jq/manual/) is a bit long, but I think the relevant part is:
The filter
contains(b)will produce true if b is completely contained within the input. A string B is contained in a string A if B is a substring of A. An array B is contained in an array A if all elements in B are contained in any element in A.jq 'contains(["baz", "bar"])' Input ["foobar", "foobaz", "blarp"] Output true