Related
I would like to add some values from json file separated by pipe. It's working well so far until a value is a number and not a string.
Here what I've done so far: jq -r '.content[] | {seasonTitle, number, name} | join("|")' file.json
I've tried to convert number to string without any success jq -r '.content[] | {seasonTitle, "episodeNumber|tostring", name} | join("|")' file.json
Actual Result:
Top Master||Last Chance / Season 12
Top Master||Épisode 8 / Season 12
Top Master||Épisode 7 / Season 12
Expected Result:
Top Master|236|Last Chance / Season 12
Top Master|235|Épisode 8 / Season 12
Top Master|234|Épisode 7 / Season 12
Here the file.json
{
"page": 0,
"size": 3,
"count": 3,
"content": [
{
"name": "Last Chance / Season 12",
"releaseDate": "2008",
"duration": 2100,
"episodeNumber": 236,
"title": "Last Chance / Season 12",
"seasonTitle": "Top Master"
},
{
"name": "Épisode 8 / Season 12",
"releaseDate": "2008",
"duration": 7320,
"episodeNumber": 235,
"title": "Épisode 8 / Season 12",
"seasonTitle": "Top Master"
},
{
"name": "Épisode 7 / Season 12",
"releaseDate": "2008",
"duration": 7200,
"episodeNumber": 234,
"title": "Épisode 7 / Season 12",
"seasonTitle": "Top Master"
}
]
}
You are using join to concatenate values of different types, which works fine under jq v1.6:
.content[] | {seasonTitle, episodeNumber, name} | join("|")
Top Master|236|Last Chance / Season 12
Top Master|235|Épisode 8 / Season 12
Top Master|234|Épisode 7 / Season 12
Demo
However, with jq v1.5 it doesn't, and you need to convert non-strings to strings using tostring. As you are using a shortcut to create an object for join, introducing this conversion sacrifices the conciseness of your solution. So either stick with it:
.content[] | {seasonTitle, episodeNumber: (.episodeNumber | tostring), name} | join("|")
Or use an array instead, as you are going for the values only anyway:
.content[] | [.seasonTitle, (.episodeNumber | tostring), .name] | join("|")
I have a table where one column is a json, like this:
{"type":"select","description":"Rota","default":"",
"required":"0","listOptions":[{"text": "1 - Jardins", "value": "1"}, {"text": "2 - Praia do Canto/Shop Vix", "value": "2"}, {"text": "3 - Hotéis Vitória/Serra", "value": "3"}, {"text": "6 - Hotéis Vila Velha/Padarias Praia da Costa", "value": "6"}, {"text": "9 - Cariacica", "value": "9"}, {"text": "5 - Vitória/Vila Velha", "value": "5"}, {"text": "10 - Baú/Reboque", "value": "10"}}
I can select like this: select atributos->"$.listOptions" from table
My question is, how can I select the values from listOptions?
Use [*] to extract all the array item values.
SELECT atributos->"$.listOptions[*].value" FROM test;
To extract a specify item use e.g first item value.
SELECT atributos->"$.listOptions[0].value" FROM test;
Refer to Runnable DBFiddle instance.
In mysql 8 you can use JSON_TABLE
CREATE tABLE TAB1 (atributos json);
INSERT INTO TAB1 VALUES ('{"type":"select","description":"Rota","default":"",
"required":"0","listOptions":[{"text": "1 - Jardins", "value": "1"}, {"text": "2 - Praia do Canto/Shop Vix", "value": "2"}, {"text": "3 - Hotéis Vitória/Serra", "value": "3"}, {"text": "6 - Hotéis Vila Velha/Padarias Praia da Costa", "value": "6"}, {"text": "9 - Cariacica", "value": "9"}, {"text": "5 - Vitória/Vila Velha", "value": "5"}, {"text": "10 - Baú/Reboque", "value": "10"}]}');
SELECT atributos->"$.description", tt1.*
FROM TAB1,
JSON_TABLE(
atributos,
"$.listOptions[*]"
COLUMNS (
mytext VARCHAR(100) PATH "$.text" DEFAULT '0' ON EMPTY DEFAULT '-99' ON ERROR,
myvalue INT PATH "$.value"
) ) tt1;
atributos->"$.description" | mytext | myvalue
:------------------------- | :--------------------------------------------- | ------:
"Rota" | 1 - Jardins | 1
"Rota" | 2 - Praia do Canto/Shop Vix | 2
"Rota" | 3 - Hotéis Vitória/Serra | 3
"Rota" | 6 - Hotéis Vila Velha/Padarias Praia da Costa | 6
"Rota" | 9 - Cariacica | 9
"Rota" | 5 - Vitória/Vila Velha | 5
"Rota" | 10 - Baú/Reboque | 10
db<>fiddle here
mysql Server (since Version 8.0):
SELECT [field with json blob]->>"$.json_field" FROM mytable;
mariaDB Server (since Version 10.26)
SELECT JSON_EXTRACT([field with json blob], "$.json_field") from mytable
We have official documentation which unclear for me without examples.
I have JSON loke this structure, its a bit bigger but the same structure, more JSONs inside the array:
WITH
responses AS (
SELECT *
FROM (VALUES ((1,
'[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "5",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "yes",
"question": "quest",
"answer_id": 10094
}
]' :: JSON),
(2,
'[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "-1",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "no",
"question": "quest",
"answer_id": 10094
}
]' :: JSON))
) TEST(id,val)
)
SELECT * from responses
I could transform to flat structure:
id| question| answer
-----------
1, 'r1', 5
1, 'q6', yes
2, 'r1', -1
2, 'q6', no
But I need to get result in this way
id| r1| q6
----------
1, 5, yes
2, -1, no
How can I get result like last one?
There are some issues with your WITH query.
First, there is no need to do "select * from (values (..))" – VALUES is itself a query which you can use without SELECT:
test=# values (1, 'zz'), (2, 'bbb');
column1 | column2
---------+---------
1 | zz
2 | bbb
(2 rows)
Next, there is an issue with parentheses. Compare the previous query with this one:
test=# values ((1, 'zz'), (2, 'bbb'));
column1 | column2
---------+---------
(1,zz) | (2,bbb)
(1 row)
If you place additional parentheses like this, you got just one row of two columns, and values in these columns being of "anonymous" record type (its Postgres type magic, very powerful, but it's different story, not needed here).
So let's fix the first part of your CTE:
with responses(id, val) AS (
values
(1, '
[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "5",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "yes",
"question": "quest",
"answer_id": 10094
}
]'::json
), (2, '
[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "-1",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "no",
"question": "quest",
"answer_id": 10094
}
]'::json
)
)
select * from responses;
Now we can use json_array_elements(..) function to extract JSON elements from the JSON arrays:
with responses(id, val) AS (
values
...
)
select id, json_array_elements(val)
from responses;
Let's use it to construct the "second stage" of our CTE:
...
), extra(id, elem) as (
select id, json_array_elements(val)
from responses
)
...
And finally, we'll get the needed result like this:
...
select
id,
elem->>'id' as json_id,
elem->>'alias' as alias,
elem->>'question' as question,
elem->>'answer' as answer
from extra;
Entire query:
with responses(id, val) AS (
values
(1, '
[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "5",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "yes",
"question": "quest",
"answer_id": 10094
}
]'::json
), (2, '
[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "-1",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "no",
"question": "quest",
"answer_id": 10094
}
]'::json
)
), extra(id, elem) as (
select id, json_array_elements(val)
from responses
)
select
id as row_id,
elem->>'id' as json_id,
elem->>'alias' as alias,
elem->>'question' as question,
elem->>'answer' as answer
from extra;
Result:
row_id | id | alias | question | answer
--------+----+-------+----------+--------
1 | 13 | r1 | qq | 5
1 | 24 | q6 | quest | yes
2 | 13 | r1 | qq | -1
2 | 24 | q6 | quest | no
(4 rows)
This is a bit different from what you wanted. What you wanted cannot be achieved with pure SQL since you want to have dynamic column names in the output -- those "r1" and "q6" must be extracted from JSON data dynamically. It's possible with plpgsql though, or with tablefunc extension to create a pivoted table, let me know if you need it.
Imagine I have a categories tree like this JSON file:
[
{
"id": "1",
"text": "engine",
"children": [
{
"id": "2",
"text": "exhaust",
"children": []
},
{
"id": "3",
"text": "cooling",
"children": [
{
"id": "4",
"text": "cooling fan",
"children": []
},
{
"id": "5",
"text": "water pump",
"children": []
}
]
}
]
},
{
"id": "6",
"text": "frame",
"children": [
{
"id": "7",
"text": "wheels",
"children": []
},
{
"id": "8",
"text": "brakes",
"children": [
{
"id": "9",
"text": "brake calipers",
"children": []
}
]
},
{
"id": "10",
"text": "cables",
"children": []
}
]
}
]
How can I convert it to this flat table?
id parent_id text
1 NULL engine
2 1 exhaust
3 1 cooling
4 3 cooling fan
5 3 water pump
6 NULL frame
7 6 wheels
8 6 brakes
9 8 brake calipers
10 6 cables
I found similar questions and inverted questions (from table to JSON) but I can't figure it out with jq and its #tsv filter. Also I noticed the "flatten" filter is not often referenced in the answers (while it looks to be the exact tool I need) but it might be because it was introduced recently in the latests versions of jq.
Here is another solution which uses jq's recurse builtin:
["id","parent_id","text"]
, (
.[]
| recurse(.id as $p| .children[] | .parent=$p )
| [.id, .parent, .text]
)
| #tsv
Sample Run (assumes filter in filter.jq and sample data in data.json)
$ jq -Mr -f filter.jq data.json
id parent_id text
1 engine
2 1 exhaust
3 1 cooling
4 3 cooling fan
5 3 water pump
6 frame
7 6 wheels
8 6 brakes
9 8 brake calipers
10 6 cables
Try it online!
The key here is to define a recursive function, like so:
def children($parent_id):
.id as $id
| [$id, $parent_id, .text],
(.children[] | children($id)) ;
With your data, the filter:
.[]
| children("NULL")
| #tsv
produces the tab-separated values shown below. It is now easy to add headers, convert to fixed-width format if desired, etc.
1 NULL engine
2 1 exhaust
3 1 cooling
4 3 cooling fan
5 3 water pump
6 NULL frame
7 6 wheels
8 6 brakes
9 8 brake calipers
10 6 cables
Here is a solution which uses a recursive function:
def details($parent):
[.id, $parent, .text], # details for current node
(.id as $p | .children[] | details($p)) # details for children
;
["id","parent_id","text"] # header
, (.[] | details(null)) # details
| #tsv # convert to tsv
Sample Run (assumes filter in filter.jq and sample data in data.json)
$ jq -Mr -f filter.jq data.json
id parent_id text
1 engine
2 1 exhaust
3 1 cooling
4 3 cooling fan
5 3 water pump
6 frame
7 6 wheels
8 6 brakes
9 8 brake calipers
10 6 cables
Try it online!
I've been looking at this tutorial and this example trying to find a performant way to query by substring with JSON (<9.5)/JSONB (*9.5) data.
For example, I have this data:
CREATE TABLE public.foo
(
row_id SERIAL PRIMARY KEY,
data json
);
INSERT INTO foo VALUES (1,
'{ "name": "Book the First", "author": "Bob", "text_entry": "White Cow Walked Over the Moon" } ');
INSERT INTO foo VALUES (2,
'{ "name": "Book the Second", "author": "Charles", "text_entry": "Humptey Dumptey sat on the Moon" } ');
INSERT INTO foo VALUES (3,
'{ "name": "Book the Third", "author": "Jim", "text_entry": "Red Fox jumped over Brown Dog" } ');
I'm looking for a way to search ONLY "text_entry" and return any case that has the sub-string "the Moon" (in this case, it would be id = 1 & 2). Expected Return:
text_entry
"White Cow Walked Over the Moon" ## has the substring "the Moon"
"Humptey Dumptey sat on the Moon" ## has the substring "the Moon"
So far my query looks like this:
SELECT data->'text_entry'->'%the Moon%' AS query FROM foo;
ERROR: cannot extract element from a scalar
********** Error **********
Is there any elegant way to query substrings in JSON/B?
I'm looking for a way to search ONLY "text_entry" and return any case that has the sub-string "the Moon"
SELECT data->>'text_entry' as query
FROM foo
WHERE data->>'text_entry' LIKE '%the Moon%';
->
query
---------------------------------
White Cow Walked Over the Moon
Humptey Dumptey sat on the Moon
(2 rows)