Use jq to remove top level module while retaining values - json

I'm trying to use jq in order to achieve the following -
With an input of:
{
"SomeValue": {
"x" : "y",
"a" : "b"
}
}
I'd like to be able to remove 'SomeValue' and return just the key/values below so that my output would look like:
{
"x" : "y",
"a" : "b"
}
I've tried various permutations of commands I've seen on the forum but either end up deleting the whole structure or nothing at all - thanks in advance for any help/pointers in the right direction.

If all you want is the content of .SomeValue, that's already exactly your filter:
jq '.SomeValue'
If this part is nested deeper, and you want to update that part while keeping the rest, use the update operator |= with .SomeValue on that context (with your small sample this is still just .):
jq '. |= SomeValue'

Related

JQ - Select JSON subarray by value then update by index

I'm trying to process some JSON output and modify a value but struggling to get anywhere.
I have no control over the source data, which looks like this:
[
[
"dave",
"likes",
"rabbits"
],
[
"brian",
"likes",
"fish"
]
]
In pseudo code, I need to:
Select the subarray with value "brian" at index 0
Change the value at index [2] in the selected array to "cats"
Return the complete modified array
I've managed to use map and select to get the subarray I want (jq -r -c 'map(select(.[]=="brian"))), but not build that into anything more useful...
Help much appreciated!
Update the required value by specifying the array indices and using the |= update select construct
map(select(.[0] == "brian")[2] |= "cats" )
This also populates [2] with "cats" even if previously there was no value at the specific index.
Of course it goes without saying, the indices could be dynamically arrived at as well
map(select(any(.[]; . == "brian"))[2] |= "cats")

JSON delete specific keys from nested objects without knowing key names

I have a json file and want to delete some subkeys i don't need. Here is some part of the JSON file :
{
"peers":{
"swp1":{
"hostname":"Spine-01",
"remoteAs":65001,
"version":4,
"msgRcvd":452,
"msgSent":459,
"tableVersion":0,
"outq":0,
"inq":0,
"peerUptime":"00:19:15",
"peerUptimeMsec":1155000,
"peerUptimeEstablishedEpoch":1635674862,
"prefixReceivedCount":30,
"pfxRcd":30,
"pfxSnt":43,
"state":"Established",
"idType":"interface"
},
"swp2":{
"hostname":"Spine-02",
"remoteAs":65001,
"version":4,
"msgRcvd":452,
"msgSent":459,
"tableVersion":0,
"outq":0,
"inq":0,
"peerUptime":"00:19:14",
"peerUptimeMsec":1154000,
"peerUptimeEstablishedEpoch":1635674863,
"prefixReceivedCount":30,
"pfxRcd":30,
"pfxSnt":43,
"state":"Established",
"idType":"interface"
}
}
}
for example, i want to delete the "version" subkey, and i already tried this command
del(.peers.swp1.version, .peers.swp2.version)
and it worked well. But the thing is, the "swp1" and "swp2" are the interfaces and are something that can change their name, increase or decrease. So I need a command that works to delete the "version" subkeys no matter what the interface name is.
All you need is map_values and del.
.peers |= map_values(del(.version))
demo in jqplay
You can also use this syntax :
del(.peers[].version)|del(.memory)

In jq, how to select objects where an array contains at least one value (intersection non-empty)

I have input like this:
{ "prop": ["apple", "banana"] }
{ "prop": ["kiwi", "banana"] }
{ "prop": ["cherry", "orange"] }
How do I print objects where prop contains at least one of kiwi and orange?
(The list of interesting values is longer than just 2, so I'd like to leverage the any function somehow.)
I've tried the following
jq 'select(any(.prop[] | contains(["kiwi", "orange"])))' < input.json
and various variants of the above, but can't figure out the right expressions.
The stream-oriented version of the built-in function any can be most easily used if one bears in mind its signature:
def any(generator; condition):
So we are led to:
select( any( .prop[]; . == "kiwi" or . == "orange" ))
or more succinctly:
select( any(.prop[]; IN("kiwi", "orange")))
whitelist
If the values of interest are provided as a JSON array, say $whitelist, you could tweak the above by substituting $whitelist[] for the explicit stream of values:
select( any(.prop[]; IN($whitelist[]) ))
I think you're looking for IN/2. It's implemented using any, but is far easier to grasp.
select(IN(.prop[]; "kiwi", "orange"))
Online demo

jq - Selecting objects containing certain key

Let's say I have this JSON file below:
{
"team": {
"money": 100,
},
"group": {
"money": 200,
"snack": true,
}
}
I want to select the objects which has a "snack" key including its parent. The current command I'm using is:
jq '..|objects|select(has("snack"))' json
This however, does not include the parent, which in this case is "group". How do I select the parent of the selected object as well?
Instead of using .., you could use paths. That is, you'd select the paths that lead to the items of interest, and work from there. So you'd start with:
paths(objects) as $p
| select(getpath($p)|has("snack"))
| $p
For the given input (after having been corrected), this would yield:
["group"]
So you might want to replace the $p in the last line by $p[-1], but it's not altogether clear how useful that would be. More useful would be getpath( $p[:-1] )

Get the element after/before the matched one in json with jq

Suppose I have the following json input to the jq command:
[
{"type":"dog", "set":"foo"},
{"type":"bird", "set":"bar"},
{"type":"cat", "set":"blaz"},
{"type":"fish", "set":"mor"}
]
I know that there is an element in this array whose type is "bird", in this case, the second element. But I want its next (or previous) sibling, that is, the element after (before) it, in this case, the third (first) element. How can I get it in jq?
Also, I have another question: If the matched element (that is, the element whose value of type I know) is the last one in the array, I want it to get the first one as next (that is, cycle through the array) instead of returning nothing. The same whether the matched element is the first one (then I want to get the last element).
For the sake of specificity, let's suppose you want to extract the the (before, focus, after) triple as an array, where before and after wrap around as described. For simplicity, let's also suppose the source array is of length at least 2.
Next, for ease of exposition and understanding, we will define a helper function for extracting the three items:
# $i is assumed to be a valid index into the input array,
# which is assumed to be of length at least 2
def triple($i):
if $i == 0 then [last] + .[0:2]
elif $i == (length-1) then .[$i-1: $i+2] + [first]
else .[$i-1: $i+2]
end;
Now we have only to find the index, and use it:
(map(.type) | index("bird")) as $i
| if $i then triple($i) else empty end
Using this approach, other variants can easily be obtained.
let me also offer you an alternative solution, based on a walk-path unix tool for JSON: jtc - there you "encode" your query logic right into the path:
e.g. to find a "type":"bird" record and then it's preceding sibling (in the parent's array) would be like this:
bash $ <file.json jtc -w'[type]:<bird> [-1]<idx>k [-1]>idx<t-1' -r
{ "set": "foo", "type": "dog" }
let me break it down for you:
[type]:<bird> - will find recursively a record "type":"bird"
[-1]<idx>k - will step up 1 tier in JSON tree (select parent, effectively select the entire record {"type":"bird", "set":"bar"}) and will memorize its array index into the namespace idx
[-1]>idx<t-1 - will again step up 1 level in JSON (selecting the top array) and will search (non-recursively) for the entry with index (stored in idx) offset by -1
Equally once can select a next sibling:
bash $ <file.json jtc -w'[type]:<bird>[-1]<idx>k[-1]>idx<t1'
{ "set": "blaz", "type": "cat" }
Or, select the first entry (based on the last match):
bash $ <file.json jtc -w'[type]:<fish>[-1]<idx>k[-1]>idx<t-1000' -r
{ "set": "foo", "type": "dog" }
(just put some surely low value as the relative quantifier - it'll get normalized to the first entry)
PS> Disclosure: I'm the creator of the jtc tool