select few elements of an inner array using jq - json

I want create a more simple json with the same original structure but with one a small sample.
As example, If I have this json:
{
"field1": [
{
"a": "F1A1",
"b": "F1B1"
},
{
"a": "F1A2",
"b": "F1B2"
},
{
"a": "F1A3",
"b": "F1B3"
},
{
"a": "F1A4",
"b": "F1B4"
}
],
"field2": [
{
"a": "F2A1",
"b": "F2B1"
},
{
"a": "F2A2",
"b": "F2B2"
}
],
"field3": [
{
"a": "F3A1",
"b": "F3B1"
},
{
"a": "F3A2",
"b": "F3B2"
}
]
}
I want to get the first array element from the first field. So I was expecting this:
{
"field1": [
{
"a": "F1A1",
"b": "F1B1"
}
],
}
I executed jq "select(.field1[0])" tmp.json but it returns the original json.
Bonus:
As bonus, how to do the same but extracting let's say field1 and elements in the array with a=="F1A1" and a=="F1A4", so will expect?:
{
"field1": [
{
"a": "F1A1",
"b": "F1B1"
},
{
"a": "F1A4",
"b": "F1B4"
}
]
}

reduce the oouter object to your field using {field1}, then map this field to an array containing only the first item:
jq '{field1} | map_values([first])'
{
"field1": [
{
"a": "F1A1",
"b": "F1B1"
}
]
}
To filter for certain items use select:
jq '{field1} | map_values(map(select(.a == "F1A1" or .a == "F1A4")))'
{
"field1": [
{
"a": "F1A1",
"b": "F1B1"
},
{
"a": "F1A4",
"b": "F1B4"
}
]
}
As you can see, select does something different. It passes on its input if the argument evaluates to true. Therefore its output is either all or nothing, never just a filtered part. (Of course, you can use select to achieve specific filtering, as shown above.)

Related

jq: Include the lookup key as a field in the result value

I have a JSON object of the following form:
{
"vars": {
"node1": {"field1": "a", "field2": "b"},
"node2": {"field1": "x", "field2": "y"}
"unrelated": {"blah": "blah"}
},
"nodes": ["node1", "node2"]
}
Now, I can get the fields per node (excluding unrelated) using the following jq expression:
.vars[.nodes[]]
Output:
{
"field1": "a",
"field2": "b"
}
{
"field1": "x",
"field2": "y"
}
My question is, how do I include the vars key as a field in the output, i.e.
{
"node": "node1",
"field1": "a",
"field2": "b"
}
{
"node": "node2",
"field1": "x",
"field2": "y"
}
The name of the key (node in the example) is not important.
Based on this post I found an approximate solution:
.vars | to_entries | map_values(.value + {node: .key})[]
which outputs
{
"field1": "a",
"field2": "b",
"node": "node1"
}
{
"field1": "x",
"field2": "y",
"node": "node2"
}
{
"blah": "blah",
"node": "unrelated"
}
But it still includes the unrelated field which is shouldn't.
Store the nodes array's elements in a variable for reference. Storing the elements rather than the whole array automatically also iterates for the next step. Then, just compose your desired output objects using the nodes array item as object {$node} added to the looked-up object in .vars[$node].
jq '.nodes[] as $node | {$node} + .vars[$node]'
{
"node": "node1",
"field1": "a",
"field2": "b"
}
{
"node": "node2",
"field1": "x",
"field2": "y"
}
Demo

graphiql only allows query if at least one element of each sublist contains queried field

I am using graphiQL to debug my react project's graphql query.
This is my query:
{
testdataJson{
E{
D{
A
B
entries
}
}
}
}
on dataset testdata.json:
{
"E": [
{
"D": [
[
{
"A": "Y1",
"entries": [
"Z1"
]
},
{
"A": "Y2",
"entries": [
"Z2"
]
}
],
[
{
"A": "Y3",
"entries": [
"Z3"
]
},
{
"A": "Y4",
"entries": [
"Z4"
],
"B": true
}
],
[
{
"A": "Y5",
"entries": [
"Z5"
],
"B": true
}
]
]
}
]
}
which gives the error: Cannot query field \"B\" on type \"TestdataJsonED\".
If I change the snippet:
[
{
"A": "Y1",
"entries": [
"Z1"
]
},
{
"A": "Y2",
"entries": [
"Z2"
]
}
],
to
[
{
"A": "Y1",
"entries": [
"Z1"
]
},
{
"A": "Y2",
"entries": [
"Z2"
]
"B": true
}
],
then everything is fine.
This seems weird as I would expect to be able to have lists which don't necessarily contain at least one element with a "B" value. In fact, my JSON data (which I did not create) has this a lot. Alternatively, this is not the cause and I have done something silly!
Cheers,
Edit: related issue - https://github.com/gatsbyjs/gatsby/issues/2392

How to filter some array in a sub-object with object in a json file with jq

I need to filter a JSON with a nested strucutre like below.
All objects in array b where attribute x contains a "z" in the value of x should be filtered out. The rest should stay in the file.
{
"a": {
"b": [
{
"c": "1",
"x": "aaa",
},
{
"c": "2",
"x": "aza",
},
{
"c": "7",
"x": "azb",
}
]
},
"d": {
"e": [
"1"
],
"f": [
"2"
]
}
}
Expected output:
{
"a": {
"b": [
{
"c": "1",
"x": "aaa"
}
]
},
"d": {
"e": [
"1"
],
"f": [
"2"
]
}
}
use select with contains:
jq '.a.b|=[.[]|select(.x|contains("z")|not)]' file

Combining JSON by common key-value pairs

I'm currently working through an issue, and can't seem to figure this one out. Here's some data so you know what I'm talking about below:
foo.json
{
"Schedule": [
{
"deviceId": 123,
"reservationId": 123456,
"username": "jdoe"
},
{
"deviceId": 456,
"reservationId": 589114,
"username": "jsmith"
}
],
"serverTime": 1522863125.019958
}
bar.json
[
{
"a": {
"b": "10.0.0.1",
"c": "hostname1"
},
"deviceId": 123
},
{
"a": {
"b": "10.0.0.2",
"c": "hostname2"
},
"deviceId": 456
}
]
foobar.json
{
"Schedule": [
{
"deviceId": 123,
"reservationId": 123456,
"username": "jdoe",
"a": {
"b": "10.0.0.1",
"c": "hostname1"
}
}
},
{
"deviceId": 456,
"reservationId": 789101,
"username": "jsmith",
"a": {
"b": "10.0.0.2",
"c": "hostname2"
}
}
],
"serverTime": 1522863125.019958
}
I'm trying to use jq to do this, and had some help from this post: https://github.com/stedolan/jq/issues/1090
The goal is to be able to combine JSON, using some key as a common point between the documents. The data may be nested any amount of levels.. In this case foo.json has nested data only two levels deep, but needs to be combined with data nested 1 level deep.
Any and all suggestions would be super helpful. I'm also happy to clarify and answer questions if needed. Thank you!
With foobar.jq as follows:
def dict(f):
reduce .[] as $o ({}; .[$o | f | tostring] = $o ) ;
($bar | dict(.deviceId)) as $dict
| .Schedule |= map(. + ($dict[.deviceId|tostring] ))
the invocation:
jq -f foobar.jq --argfile bar bar.json foo.json
yields the output shown below.
Notice that the referents in the dictionary contain the full object (including the key/value pair for "deviceId"), but it's not necessary to del(.deviceId) because of the way + is defined in jq.
Output
{
"Schedule": [
{
"deviceId": 123,
"reservationId": 123456,
"username": "jdoe",
"a": {
"b": "10.0.0.1",
"c": "hostname1"
}
},
{
"deviceId": 456,
"reservationId": 589114,
"username": "jsmith",
"a": {
"b": "10.0.0.2",
"c": "hostname2"
}
}
],
"serverTime": 1522863125.019958
}

Parsing float value from string by jq

I have a particular JSON data which contain float value that I need to conditionally process over an array of JSON. This is an example of one JSON instance:
[
{
"a": "0",
"b": "66.67",
"c": "0",
"d": "0"
},
{
"a": "12.33",
"b": "0",
"c": "60.2",
"d": "19.3"
},
{
"a": "70.0",
"b": "92.67",
"c": "0",
"d": "0"
}
]
and I wish to conditionally select like
cat mydata.json | jq '.[] | select((.a > 50) and (.b > 50))'
and it should sound like
{
"a": "70.0",
"b": "92.67",
"c": "0",
"d": "0"
}
The problem is my original data is a string value and I have no idea how to parse it for a conditional selection.
Simply with jq's tonumber function:
jq '.[] | select((.a|tonumber) > 50 and (.b|tonumber) > 50)' mydata.json
The output:
{
"a": "70.0",
"b": "92.67",
"c": "0",
"d": "0"
}