filtering a nested array with jq - json

I've got the following JSON:
{
"x": [
{ "a": 1 },
{ "a": 2 },
{ "b": 1 },
{ "b": 2 }
]
}
I want to filter it so that I get back:
{
"x": [
{ "b": 1 },
{ "b": 2 }
]
}
I've tried
".x[] | select(.b)"
But, that gives me back just a list of the objects with b as so:
{ "b": 1 }
{ "b": 2 }
I want the original surrounding object as well. (The full JSON is much larger and with much deeper nesting.)

Unfortunately your general requirements are unclear, but hopefully the following solution to the class of problems suggested by the example will provide the guidance you seek:
.x |= map(select(has("b")))

Related

jq: how to change structure of JSON avoiding cartesian product?

I have thin JSON input:
[
{
"x": [
"2020-02-24T00:00:00",
"2020-02-25T00:00:00",
"2020-02-26T00:00:00"
],
"y": [
3,
2,
6
]
}
]
And I would like to obtain:
[
{
"a": "2020-02-24T00:00:00",
"b": 3
},
{
"a": "2020-02-25T00:00:00",
"b": 2
},
{
"a": "2020-02-26T00:00:00",
"b": 6
}
]
If I apply .[]|{a:.x[],b:.y[]} I obtain the cartesian product (9 items).
How to change the structure of this JSON avoiding cartesian product?
Introducing a single "$-variable" keeps things brief and straightforward:
map(range(0; .x|length) as $i
| {a: .x[$i], b: .y[$i]})
but a $-variable free solution only requires one more line:
map([.x, .y]
| transpose[]
| {a: .[0], b: .[1]})

How to "number" array items? [duplicate]

This question already has answers here:
How do i add an index in jq
(3 answers)
Closed 2 years ago.
Considering input:
[
{
"a": 1
},
{
"a": 2
},
{
"a": 7
}
]
how do I add new field to each object, which value would be index in array? Producing:
[
{
"a": 1,
"index": 0
},
{
"a": 2,
"index": 1
},
{
"a": 7,
"index": 2
}
]
Using reduce, without disassembling/reassembling the input:
reduce range(length) as $index (.; .[$index] += {$index})
Online demo
Store the structure into a variable, then use keys to get the indices, retrieve the corresponding object from the variable using the index and add the index to it:
jq '[ . as $d | keys[] | $d[.] + {index:.} ]' file.json
to_entries takes an object and returns an array of key/value pairs.
It can be used effectively and intuitively.
jq/to_entries
input file
// file.json
[
{
"a": 1
},
{
"a": 2
},
{
"a": 7
}
]
commands
jq 'to_entries | map(.value+{index:.key})' file.json
results
[
{
"a": 1,
"index": 0
},
{
"a": 2,
"index": 1
},
{
"a": 7,
"index": 2
}
]
Here's also an alternative (non-jq) solution, using jtc:
bash $ <input.json jtc -w'[:]<I>k' -i'{"index":{I}}'
[
{
"a": 1,
"index": 0
},
{
"a": 2,
"index": 1
},
{
"a": 7,
"index": 2
}
]
bash $
PS. I'm a developer of jtc - unix JSON processor
PPS. The disclaimer is required by SO.
Try : Array[index_of_object].property = value
for example : array[0].a = 1

Conditional deletion from array of field A with condition on field B

Let's say I have a json with an array inside. Say that the elements of this array are objects with keys A and B. I would like to remove the B objects on the elements where A objects meet a certain condition.
For example, I would like to remove the B objects where A is greater than 5, transforming
{
"title": "myTitle",
"myArray": [
{
"A": 1,
"B": "foo"
},
{
"A": 4,
"B": "bar"
},
{
"A": 7,
"B": "barfoo"
},
{
"A": 9,
"B": "foobar"
}
]
}
into
{
"title": "myTitle",
"myArray": [
{
"A": 1,
"B": "foo"
},
{
"A": 4,
"B": "bar"
},
{
"A": 7
},
{
"A": 9
}
]
}
The task seems easy enough and if I had't have to keep the A's it would be a simple del(select..) thing. There surely must be an elegant way to do this as well?
Thank you!
You can still use a del(select..) thing.
.myArray[] |= del(select(.A > 5) .B)
demo at jqplay.org

How can you sort a JSON object efficiently using JQ

I've got JSON in the format
{
"a": {
"size":3
},
"b": {
"size":2
},
"c": {
"size":1
}
}
I need to sort it by size, e.g.:
{
"c": {
"size": 1
},
"b": {
"size": 2
},
"a": {
"size": 3
}
}
I have found a way to do it, e.g.:
. as $in | keys_unsorted | map ({"key": ., "size" : $in[.].size}) | sort_by(.size) | map(.key | {(.) : $in[.]}) | add
but this seems quite complex so I'm hoping there's a simpler way that I've overlooked?
You can use to_entries / from_entries, like this:
jq 'to_entries|sort_by(.value.size)|from_entries' file.json
to_entries will transform your input object into a list of key/value pair objects:
[
{
"key": "a",
"value": {
"size": 3
}
},
...
{
"key": "c",
"value": {
"size": 1
}
}
]
That allows to apply sort_by(.value.size) to that list and then convert it back to an object using from_entries.

Representing a graph in JSON

Inspired by this question, I'm trying to represent a DAG in JSON. My case includes edges and nodes that contain some data (rather than just strings as in this example). I was thinking of a spec like this:
{
"graph": {
"a": ["b", "c"],
"b": ["c"]
"c"
},
"nodes": {
"a": {
"name": "Adam"
},
"b": {
"name": "Bob"
},
"c": {
"name": "Caillou"
}
},
"edges": {
// how to do the same for edges?
// ie: how to query edges ?
}
}
One idea I had was to make the keys of the edges be the concatenation of the two vertex ids that it connects. For example, ab, ac, and bc are the three edges in this graph. I want to know if there's a more standard way of doing this.
EDIT: This is what I'm thinking of now
{
"graph": {
"a": {
"data": {
// a's vertex data
},
"neighbors": {
"b": {
"data": {
// data in edge ab
}
},
"c": {
"data": {
// data in edge ac
}
}
}
},
"b": {
"data": {
// b's vertex data
},
"neighbors": {
"c": {
"data": {
// data in edge bc
}
}
}
},
"c": {
"data": {
// c's vertex data
}
}
}
}
Since the DAG's edges hold data, they better have their own identifiers, just like the nodes. That is, the json representation should be composed of three components:
Node records: mapping each node identifier to the node's data.
Edge records: mapping each edge identifier to the edge's data.
Adjacency lists: mapping each node identifier to an array of edge identifiers, each corresponds to an edge going out of the node.
DAG = {
"adjacency": {
"a": ["1", "2"],
"b": ["3"]
},
"nodes": {
"a": {
// data
},
"b": {
// data
},
"c": {
// data
}
},
"edges": {
"1": {
"from": "a", "to": "b",
"data": {
// data
}
},
"2": {
"from": "a", "to": "b",
"data": {
// data
}
},
"3": {
"from": "b", "to": "c",
"data": {
// data
}
}
}
}
Turns out there are standards that are trying to emerge for this sort of thing. I recently had to look these up for a project of my own. You might be interested in http://jsongraphformat.info/ for example, or one of the peer projects it references on its website. Goals include trying to represent in JSON anything you can represent in the DOT language (https://en.wikipedia.org/wiki/DOT_(graph_description_language)).
json-ld was made for this. It has a semi-steep learning curve, but it is a robust way to represent graph data in json.