I want to transform following type of json obj
[
{
"A": "a",
"Tags": [
{ "key":"x", "value":0},
{ "key":"y", "value":1},
]
},
{...}
]
to this, including Tags list on top
[
{
"A": "a",
"x": 0,
"y": 1
},
{...}
]
I try to use JQ but without result.
map(. + (.Tags | from_entries) | del(.Tags))
Will map() over all the objects in the array and:
Convert .Tags to an object using from_entries
This is added to the original object (. + ())
Delete the original .Tags
Output:
[
{
"A": "a",
"x": 0,
"y": 1
}
]
Online Demo
Related
Given the following input:
{
"text": "a1\nb2"
}
How do I get the following output:
[
{
"letter": "a",
"number": 1
},
{
"letter": "b",
"number": 2
}
]
I've tried using capture with the "g" flag, but this yields two documents instead of a single document with an array of captured inputs:
$ echo '{
"text": "a1\\nb2"
}' | jq '.text | capture("(?<letter>[a-z])(?<number>[0-9])";"g")'
{
"letter": "a",
"number": "1"
}
{
"letter": "b",
"number": "2"
}
Here is a link to the jqplay example.
Why not just wrap the capture in a new array:
.text | [ capture("(?<letter>[a-z])(?<number>[0-9])";"g") ]
JqPlay
The simplest version of the input document I could come up with is
{
"references": [
{
"version": 5,
"id": "id1",
"objType": "A"
},
{
"version": 4,
"id": "id2",
"objType": "B",
"referencing": []
},
{
"version": 4,
"id": "id3",
"objType": "B",
"referencing": [
{
"version": 2,
"id": "id4",
"objType": "A"
},
{
"version": 3,
"id": "id5",
"objType": "B",
"referencing": []
}
]
}
]
}
Objects of type A have no referencing objects.
Objects of type B can be referenced by either type of object.
There are two outputs I need from this json:
Output #1 is the version info for objects of type A with the id value as a key with the value of version. A objects can be at the top level or at some arbitrary depth in the referencing arrays.
{
"references": {
"id1": {"version": 5},
"id4": {"version": 2}
}
}
The 2nd output is similar: the version info for objects of type B. The can be a chain of type B objects referencing other type B objects.
{
"references": {
"id2": {"version": 4},
"id3": {"version": 4},
"id5": {"version": 3}
}
}
Use recursive decsent operator and from_entries. You don't need to follow the "references" (at least not to produce the expected output in your question)
{
dependencies: [.. | select(.objType=="A")? | { key: .id, value: {version} }] | from_entries
},
{
dependencies: [.. | select(.objType=="B")? | { key: .id, value: {version} }] | from_entries
}
Output:
{
"dependencies": {
"id1": {
"version": 5
},
"id4": {
"version": 2
}
}
}
{
"dependencies": {
"id2": {
"version": 4
},
"id3": {
"version": 4
},
"id5": {
"version": 3
}
}
}
It's also possible to merge (add) objects instead of constructing them from their entries, which makes the code minimally shorter:
{
dependencies: [.. | select(.objType=="A")? | { (.id): {version} }] | add
}
You can use recurse to traverse the document, INDEX to create an object with IDs as keys, map_values to format their values using select to reduce according to your criteria.
jq --arg type A '
.references |= (
INDEX(.[] | recurse(.referencing[]?); .id)
| map_values(select(.objType == $type) | {version})
)
'
{
"references": {
"id1": {
"version": 5
},
"id4": {
"version": 2
}
}
}
Demo
This works for both questions, provide A or B to --arg type.
Note that this is using the error suppression operator ? when recursing down. If you want to restrict the traversal explicitly to .objType == "B", just prepend it in a select expression, i.e. replace recurse(.referencing[]?) with recurse(select(.objType == "B") | .referencing[]). Demo
Example json data:
{
"data": [
{
"place": "FM346",
"id": [
"7_day_A",
"7_day_B",
"7_day_C",
"7_day_D"
],
"values": [
0,
30,
23,
43
]
},
{
"place": "LH210",
"id": [
"1_day_A",
"1_day_B",
"1_day_C",
"1_day_D"
],
"values": [
4,
45,
100,
9
]
}
]
}
what i need to transform it into:
{
"data": [
{
"place": "FM346",
"7_day_A": {
"value": 0
},
"7_day_B": {
"value": 30
},
"7_day_C": {
"value": 23
},
"7_day_D": {
"value": 43
}
},
{
"place": "LH210",
"1_day_A": {
"value": 4
},
"1_day_B": {
"value": 45
},
"1_day_C": {
"value": 100
},
"1_day_D": {
"value": 9
}
}
]
}
i have tried this:
{
data:[.data |.[]|
{
place: (.place),
(.id[]):
{
value: (.values[])
}
}]
}
(in jqplay: https://jqplay.org/s/f4BBtN9gwmp)
and this:
{
data:[.data |.[]|
{
place: (.place),
test:
[{
(.id[]):
{
value: (.values[])
}
}]
}]
}
(in jqplay: https://jqplay.org/s/pKIvQe1CzgX)
but they arent grouped in the way i wanted and it gives each value to each id, not the corresponding one.
I have been trying for some time now, but im new to jq and have no idea how to transform it this way, thanks in advance for any answers.
You can use transpose here, which can play a key role in converting the arrays to key/value pairs
.data[] |= {place} +
([ .id, .values ] | transpose | map({(.[0]): { value: .[1] } }) | add)
The solution works by converting the array-of-arrays [.id, .values] by transposing them, i.e. converting
[["7_day_A","7_day_B","7_day_C","7_day_D"],[0,30,23,43]]
[["1_day_A","1_day_B","1_day_C","1_day_D"],[4,45,100,9]]
to
[["7_day_A",0],["7_day_B",30],["7_day_C",23],["7_day_D",43]]
[["1_day_A",4],["1_day_B",45],["1_day_C",100],["1_day_D",9]]
With the transformation done, we construct an object with key as the zeroth index element and value as an object comprising of the value of first index element, and combine the results together with add
Demo - jqplay
Suppose I have an object like:
{
"a": 1,
"b": 2,
"c": [
{
"d": 1,
"e": 2
},
{
"d": 2,
"e": 3
}
]
}
and I wish to extract only a set of keys (which are possibly nested), like .a and .c[].d, giving us the following output:
{
"a": 1,
"c": [
{
"d": 1
},
{
"d": 2
}
]
}
How would I go about doing that?
Here are two possible ways to do it:
Explicitly extracting the keys (like in this question), e.g.:
$ jq '{a, c: .c[] | {d}}' test.json
{
"a": 1,
"c": {
"d": 1
}
}
{
"a": 1,
"c": {
"d": 2
}
}
which works but can get ugly very quickly if you try to use it with long keys or deeply nested sub-objects.
Note that selecting paths that don't exist will result in null:
$ jq '{a, c: .c[] | {f}}' test.json
{
"a": 1,
"c": {
"f": null
}
}
{
"a": 1,
"c": {
"f": null
}
}
Implementing pick function to filter an object for specific keys:
def pick(paths):
. as $root |
reduce path(paths) as $path
({}; setpath($path; $root | getpath($path)));
Resulting in:
$ jq "$(cat query.jq)"' pick(.a, .c[].f, .c[].d)' test.json
{
"a": 1,
"c": [
{
"f": null,
"d": 1
},
{
"f": null,
"d": 2
}
]
}
If we'd like non-existent paths to be omitted instead of set to null, we can add haspath function to check if a path exists inside an object like so:
def haspath($path):
def h:
. as [$json, $p]
| (($p|length)==0) or
($json | (has($p[0]) and ( [getpath([$p[0]]), $p[1:] ] | h)));
[., $path] | h;
def pick(paths):
. as $root |
reduce path(paths) as $path
({}; if $root|haspath($path) then . + setpath($path; $root | getpath($path)) else . end);
Resulting in:
$ jq "$(cat query_haspath.jq)"' pick(.a, .c[].f, .c[].d)' test.json
{
"a": 1,
"c": [
{
"d": 1
},
{
"d": 2
}
]
}
I would like to find a better way to search for if documents in a collection have a property with more than 0 elements in the array, i.e. anything that isn't empty.
such as: select * from c where c.property = 'x' and array_length(c.child) > 0 and array_length(c.child.grandchild) > 0
The first arraylength works. Adding the second with just this dot notation doesn't work as I read somewhere else. How can I ensure that I can accomplish this. The grandchild will be anywhere from 0 to many number where it has a greater array length than 0.
Please let me know if more clarification is needed.
Please use below sql :
SELECT distinct c.id,c.name,c.child FROM c
join child in c.child
where array_length(c.child) > 0
and array_length(child.grandchild) > 0
My sample documents:
[
{
"id": "1",
"name": "Jay",
"child": [
{
"name": "A",
"grandchild": [
{
"name": "A1"
},
{
"name": "A2"
}
]
},
{
"name": "B",
"grandchild": [
{
"name": "B1"
},
{
"name": "B2"
}
]
}
]
},
{
"id": "2",
"name": "Tom",
"child": [
{
"name": "A",
"grandchild": []
},
{
"name": "B",
"grandchild": []
}
]
}
]
Hope it helps you.