Problem with jq doing a select and contains - jq

I have limited experience with jq and am having an issue doing a a select contains for a string in a boolean. This is my json and am looking to get back just tdonn.
[
"user",
"admin"
]
[
[
"tdonn",
true
]
]
Here is what im trying. I have tried many different ways too.
jq -e -r '.results[] | .series[] | select(.values[] | contains("tdon"))[]'

With the sample JSON shown in a comment, the following filter would produce the result shown:
.results[] | .series[][] | flatten[] | select(contains("tdon")?)
Output with -r option
tdonn

You might like to consider:
jq '.. | strings | select(contains("tdon"))'

Related

How does one display the recursive search key in jq after a recursive search involving multiple keys?

Given the following JSON:
{ 'doc': 'foobar',
'pages': [
{ 'data': { 'keyA': { 'foo': 'foo', 'bar': 'bar' }, 'keyB': {'A':'123', 'B': 'c'} },
...
]
}
I am performing the following jq search:
#!/usr/bin/jq -f
.. | .keyA?, .keyB?
Which is great:
{'foo': 'foo', 'bar': 'bar'} # pretend it is formatted
{'A': '123', 'B': 'c'}
But now I'd like to format the output like:
{'key': 'keyA', 'value': {...}}
{'key': 'keyB', 'value': {...}}
However, there doesn't seem to be a reasonable way to use the recursive operator .. and do this.
Instead, I'll have to run N-independent searches for the N keys to have them all separated out. This is painful.
Is it possible to reform the data so that the output of the search function gets labeled with the key that yielded the object?
You can use object construction:
$ jq -c '.. | { keyA, keyB }?' sample.json
{"keyA":null,"keyB":null}
{"keyA":null,"keyB":null}
{"keyA":{"foo":"foo","bar":"bar"},"keyB":{"A":"123","B":"c"}}
{"keyA":null,"keyB":null}
{"keyA":null,"keyB":null}
Which you can then filter out:
$ jq -c '.. | { keyA, keyB }? | to_entries[] | select(.value)' sample.json
{"key":"keyA","value":{"foo":"foo","bar":"bar"}}
{"key":"keyB","value":{"A":"123","B":"c"}}
to_entries will turn an object into an array of key-value pairs. Then, checking the key name explicitly enables you to also find values of null. The -c flag makes the output "compact".
#!/usr/bin/env -S jq -c -f
.. | objects | to_entries[] | select(.key == ("keyA", "keyB"))
{"key":"keyA","value":{"foo":"foo","bar":"bar"}}
{"key":"keyB","value":{"A":"123","B":"c"}}

Trying to get the correct output from JQ

I'm trying to get this output the device name "test"
My filter is .[] | [.deviceName] and it's returning error: (at :7): Cannot index array with string "deviceName"
{
"test": [
{
"deviceName": "test",
"monitoringServer": "server1"
}
]
}
Presumably you meant:
jq '.test[] | [.deviceName]'
or perhaps:
jq '.[][] | [.deviceName]'
but without knowing your requirements, it's hard to say. That's one of the reasons why the http://stackoverflow.com/help/mcve guidelines were formulated.

jq using contains method when text value has quote literal

I'm trying to use jq to filter my results when the value contains quote literals so my data looks like:
{"key": "site=\"abc\""}
I want to filter using contains (or some other method) for where site=abc but not site=abc123
current code that gets abc and abc123:
jq -c '.textPayload | select(contains("abc"))' test.json
I attempted to try to escape using \ but it looks like it doesn't work in the contains method?
Consider:
$ echo '{"key": "site=\"abc\""}' | jq 'select(.key | contains("\"abc\""))'
{
"key": "site=\"abc\""
}
$ echo '{"key": "site=\"abc\""}' | jq 'select(.key | index("\"abc\""))'
{
"key": "site=\"abc\""
}
$ echo '{"key": "site=\"abc\""}' | jq 'select(.key | test("\"abc\""))'
{
"key": "site=\"abc\""
}
So it's unclear what the difficulty is.

Passing regular expression from variable in jq

I'm trying to filter AWS ECR image list returned as JSON with jq and regular expressions.
Following command work as expected and return filtered list:
aws ecr list-images --registry-id 123456789012 --repository-name repo | jq '.imageIds | map(select(.imageTag)) | map(select(.imageTag | test("[a-z0-9]-[0-9]")))'
[
{
"imageTag": "bbe3d9-2",
"imageDigest": "sha256:4c0e92098010fd26e07962eb6e9c7d23315bd8f53885a0651d06c2e2e051317d"
},
{
"imageTag": "3c840a-1",
"imageDigest": "sha256:9d05e04ccd18f2795121118bf0407b0636b9567c022908550c54e3c77534f8c1"
},
{
"imageTag": "1c0d05-141",
"imageDigest": "sha256:a62faabb9199bfc449f0e0a6d3cdc9be57b688a0890f43684d6d89abcf909ada"
}
]
But when I try to pass regular expression as an argument to jq it return an empty array.
aws ecr list-images --registry-id 123456789012 --repository-name repo | jq --arg reg_exp "[a-z0-9]-[0-9]" '.imageIds | map(select(.imageTag)) | map(select(.imageTag | test("$reg_exp")))'
[]
I have tried multiple ways to pass that variable, but just can't get it work. Other relevant information may be that I'm using zsh on mac and my jq version is jq-1.5. Any help is appreciated.
$reg_exp is a variable referring to your regular expression, "$reg_exp" is just a literal string. Remove the quotes. (and that extra map/select is redundant)
jq --arg reg_exp "[a-z0-9]-[0-9]" '.imageIds | map(select(.imageTag | test($reg_exp)))'

Passing Multiple Objects to jq for Recursive Filter Operation

I am trying to use jq 1.5 to develop a script that can take one or more user inputs that represent a key and recursively remove them from JSON input.
The JSON I am referencing is here:
https://github.com/EmersonElectricCo/fsf/blob/master/docs/Test.json
My script, which seems to work pretty well, is as follows.
def post_recurse(f):
def r:
(f | select(. != null) | r), .;
r;
def post_recurse:
post_recurse(.[]?);
(post_recurse | objects) |= del(.META_BASIC_INFO)
However, I would like to replace META_BASIC_INFO with one or more user inputs. How would I go about accomplishing this? I presume with --arg from the command line, but I am unclear on how to incorporate this into my .jq script?
I've tried replacing del(.META_BASIC_INFO) with del(.$module) and invoking with cat test.json | ./jq -f fsf_key_filter.jq --arg module META_BASIC_INFO to test but this does not work.
Any guideance on this is greatly appreciated!
ANSWER:
Based on a couple of suggestions I was able to arrive to the following that works and users JQ.
Innvocation:
cat test.json | jq --argjson delete '["META_BASIC_INFO","SCAN_YARA"]' -f fsf_module_filter.jq
Code:
def post_recurse(f):
def r:
(f | select(. != null) | r), .;
r;
def post_recurse:
post_recurse(.[]?);
(post_recurse | objects) |= reduce $delete[] as $d (.; delpaths([[ $d ]]))
It seems the name module is a keyword in 1.5 so $module will result in a syntax error. You should use a different name. There are other builtins to do recursion for you, consider using them instead of churning out your own.
$ jq '(.. | objects | select(has($a))) |= del(.[$a])' --arg a "META_BASIC_INFO" Test.json
You could also use delpaths/1. For example:
$ jq -n '{"a":1, "b": 1} | delpaths([["a"]])'
{
"b": 1
}
That is, modifying your program so that the last line reads like this:
(post_recurse | objects) |= delpaths([[ $delete ]] )
you would invoke jq like so:
$ jq --arg delete "META_BASIC_INFO" -f delete.jq input.json
(One cannot use --arg module ... as "$module" has some kind of reserved status.)
Here's a "one-line" solution using walk/1:
jq --arg d "META_BASIC_INFO" 'walk(if type == "object" then del(.[$d]) else . end)' input.json
If walk/1 is not in your jq, here is its definition:
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
If you want to recursively delete a bunch of key-value pairs, then here's one approach using --argjson:
rdelete.jq:
def rdelete(key):
walk(if type == "object" then del(.[key]) else . end);
reduce $strings[] as $s (.; rdelete($s))
Invocation:
$ jq --argjson strings '["a","b"]' -f rdelete.jq input.json

Resources