Querying JSONB using Postgres - json

I am attempting to get an element in my JSON with a query.
I am using Groovy, Postgres 9.4 and JSONB.
Here is my JSON
{
"id": "${ID}",
"team": {
"id": "123",
"name": "Shire Soldiers"
},
"playersContainer": {
"series": [
{
"id": "1",
"name": "Nick",
"teamName": "Shire Soldiers",
"ratings": [
1,
5,
6,
9
],
"assists": 17,
"manOfTheMatches": 20,
"cleanSheets": 1,
"data": [
3,
2,
3,
5,
6
],
"totalGoals": 19
},
{
"id": "2",
"name": "Pasty",
"teamName": "Shire Soldiers",
"ratings": [
6,
8,
9,
10
],
"assists": 25,
"manOfTheMatches": 32,
"cleanSheets": 2,
"data": [
3,
5,
7,
9,
10
],
"totalGoals": 24
}
]
}
}
I want to fetch the individual elements in the series array by their ID, I am currently using this query below
select content->'playersContainer'->'series' from site_content
where content->'playersContainer'->'series' #> '[{"id":"1"}]';
However this brings me back me back both the element with an id of 1 and 2
Below is what I get back
"[{"id": "1", "data": [3, 2, 3, 5, 6], "name": "Nick", "assists": 17, "ratings": [1, 5, 6, 9], "teamName": "Shire Soldiers", "totalGoals": 19, "cleanSheets": 1, "manOfTheMatches": 20}, {"id": "2", "data": [3, 5, 7, 9, 10], "name": "Pasty", "assists": 25, "r (...)"
Can anyone see where I am going wrong? I have seen some other questions on here but they don't help with this.

content->'playersContainer'->'series' is an array. Use jsonb_array_elements() if you want to find a specific element in an array.
select elem
from site_content,
lateral jsonb_array_elements(content->'playersContainer'->'series') elem
where elem #> '{"id":"1"}';
Test it here.

Related

Transforming the JSON using JOLT

I am trying to process a nested JSON and flatten it in Apache NiFi, with the help of the JoltTransformation processor by supplying a spec.
Sample JSON:
Input
{
"product": "astro",
"init": "2022091400",
"dataseries": [
{
"timepoint": 3,
"cloudcover": 2,
"seeing": 6,
"transparency": 2,
"lifted_index": 2,
"rh2m": 3,
"wind10m": {
"direction": "N",
"speed": 3
},
"temp2m": 33,
"prec_type": "none"
},
{
"timepoint": 6,
"cloudcover": 2,
"seeing": 6,
"transparency": 2,
"lifted_index": 2,
"rh2m": 1,
"wind10m": {
"direction": "NW",
"speed": 3
},
"temp2m": 35,
"prec_type": "none"
},
{
"timepoint": 9,
"cloudcover": 1,
"seeing": 6,
"transparency": 2,
"lifted_index": 2,
"rh2m": 2,
"wind10m": {
"direction": "N",
"speed": 3
},
"temp2m": 35,
"prec_type": "none"
}
]
}
Jolt Spec
[
{
"operation": "shift",
"spec": {
"product": "product",
"init": "init",
"dataseries": {
"*": {
"timepoint": "timepoint",
"cloudcover": "cloudcover",
"seeing": "seeing",
"transparency": "transparency",
"lifted_index": "lifted_index",
"rh2m": "rh2m",
"wind10m": {
"direction": "direction",
"speed": "speed"
},
"temp2m": "temp2m",
"prec_type": "prec_type"
}
}
}
}
]
Output
{
"product" : "astro",
"init" : "2022091400",
"timepoint" : [ 3, 6, 9 ],
"cloudcover" : [ 2, 2, 1 ],
"seeing" : [ 6, 6, 6 ],
"transparency" : [ 2, 2, 2 ],
"lifted_index" : [ 2, 2, 2 ],
"rh2m" : [ 3, 1, 2 ],
"direction" : [ "N", "NW", "N" ],
"speed" : [ 3, 3, 3 ],
"temp2m" : [ 33, 35, 35 ],
"prec_type" : [ "none", "none", "none" ]
}
Expected Output
{
"product" : "astro",
"init" : "2022091400",
"timepoint" : 3,
"cloudcover" : 2,
"seeing" : 6,
"transparency" : 2,
"lifted_index" : 2,
"rh2m" : 3,
"direction" : "N",
"speed" : 3,
"temp2m" : 33,
"prec_type" : "none"
},
{
"product" : "astro",
"init" : "2022091400",
"timepoint" : 6,
"cloudcover" : 2,
"seeing" : 6,
"transparency" : 2,
"lifted_index" : 2,
"rh2m" : 1,
"direction" : "NW",
"speed" : 3,
"temp2m" : 35,
"prec_type" : "none"
},
{
"product" : "astro",
"init" : "2022091400",
"timepoint" : 9,
"cloudcover" : 1,
"seeing" : 6,
"transparency" : 2,
"lifted_index" : 2,
"rh2m" : 2,
"direction" : "N",
"speed" : 3,
"temp2m" : 35,
"prec_type" : "none"
}
So my expectation is to have flatten the JSON and have single values for each main object in this case product and init, after which I plan to send this over to the ConvertJsontoSql processor within the NiFi to have the records inserted into PostgresDB.
https://jolt-demo.appspot.com/
No need to write each attribute individually, but just use # and & wildcards, except for product and init those should be taken after going the tree two levels up such as
[
{
"operation": "shift",
"spec": {
"dataseries": {
"*": {
"#(2,product)": "[&1].product",
"#(2,init)": "[&1].init", // 2 stands for reaching the level of the "init" aatribute, [&1] is for reaching the level of indexes of "dataseries" array and shaping the result as array(nested within square brackets)
"*": "[&1].&",
"w*": {
"*": "[&2].&"
}
}
}
}
}
]
the demo on the site http://jolt-demo.appspot.com/ is :

How produces statistics with laravel?

I work on a laravel application that is a bit like a quiz. You create an exercise, you add questions and each question to answers.
Until then everything is fine.
My interest is to present statistics for each exercise after schoolchildren have answered the tests.
I want to be able to display the answer percentage for each question.
Here is an example of the data structure I have:
[
{
"id": 1,
"exercice_id": 1,
"question": "Lorem ipsum ?",
"responses": [
{
"id": 1,
"exercice_id": 1,
"question_id": 1,
"response_text": "Yes",
},
{
"id": 2,
"exercice_id": 1,
"question_id": 1,
"response_text": "No",
}
],
"choice": [
{
"id": 1,
"exercice_id": 1,
"question_id": 1,
"response_id": 1,
},
{
"id": 2,
"exercice_id": 1,
"question_id": 1,
"response_id": 1,
},
{
"id": 3,
"exercice_id": 1,
"question_id": 1,
"response_id": 2,
}
]
},
{
"id": 2,
"exercice_id": 1,
"question": "fake text ?",
"responses": [
{
"id": 3,
"exercice_id": 1,
"question_id": 2,
"response_text": "A",
},
{
"id": 4,
"exercice_id": 1,
"question_id": 2,
"response_text": "B",
},
{
"id": 5,
"exercice_id": 1,
"question_id": 2,
"response_text": "C",
}
],
"choice": [
{
"id": 4,
"exercice_id": 1,
"question_id": 2,
"response_id": 5,
},
{
"id": 5,
"exercice_id": 1,
"question_id": 2,
"response_id": 3,
}
]
}
]
I tried the groupBy method on several elements. but I have not found the formula yet.
return response()->json(Question::with('responses','choice')
->where('exercice_id',$exo->id)
//->groupBy('choice')
->get(),
200,[], JSON_NUMERIC_CHECK);

load json data in vue

I am trying to load my data/data.json file to my component so that I can display the data when a particular part is clicked.
Snippet of my data
"colors": [
{"id": 1, "type": "direct", "primary": "red", "hex": [1, 4]},
{"id": 2, "type": "direct", "primary": "yellow", "hex": [2, 5]},
{"id": 3, "type": "direct", "primary": "blue", "hex": [3, 6]},
{"id": 4, "type": "split", "primary": "red", "hex": [1, 7, 8]},
{"id": 5, "type": "split", "primary": "yellow", "hex": [2, 9, 10]},
{"id": 6, "type": "split", "primary": "blue", "hex": [3, 11, 12]},
{"id": 7, "type": "analogous", "primary": "red", "hex": [1, 13, 14]},
{"id": 8, "type": "analogous", "primary": "yellow", "hex": [2, 15, 16]},
{"id": 9, "type": "analogous", "primary": "blue", "hex": [3, 17, 18]}
]
I have a another data set that is connected to the hex data that's why they are just numbered
For the loading in the data, I have it as follows:
var app = new Vue({
el:"#app",
data:function() {
return{
json: null
}
},
methods: {
}
});
$.getJSON('data/data.json', function (json) {
app.json = json;
});
What is a good way to add it to my components so that I can properly display what data I am wanting to show?
You could load it within the component itself once it's mounted, using the mounted hook:
// ...
data () {
return { json: null }
},
mounted () {
$.getJSON('data/data.json', json => {
this.json = json
})
}

Query JSON in Postgres

I have some JSON in my postgres DB, it's in a table called site_content, the table has two rows, id and content, in content is where I store my JSON. I want to be able to find the a player given his id, my players are stored under the key series as this is the key needed to create my charts from JSON.
Here is the query I am currently using:
Blocking.get {
sql.firstRow("""SELECT * from site_content where content -> 'playersContainer' -> 'series' -> 'id' = ${id} """)
}.map { row ->
log.info("row is: ${row}")
if (row) {
objectMapper.readValue(row.getAt(0).toString(), Player)
}
}
}
However I get back this error:
org.postgresql.util.PSQLException: ERROR: operator does not exist:
json = character varying Hint: No operator matches the given name
and argument type(s). You might need to add explicit type casts.
Here is an example of my JSON:
"id": "${ID}",
"team": {
"id": "123",
"name": "Shire Soldiers"
},
"playersContainer": {
"series": [
{
"id": "1",
"name": "Nick",
"teamName": "Shire Soldiers",
"ratings": [
1,
5,
6,
9
],
"assists": 17,
"manOfTheMatches": 20,
"cleanSheets": 1,
"data": [
3,
2,
3,
5,
6
],
"totalGoals": 19
},
{
"id": "2",
"name": "Pasty",
"teamName": "Shire Soldiers",
"ratings": [
6,
8,
9,
10
],
"assists": 25,
"manOfTheMatches": 32,
"cleanSheets": 2,
"data": [
3,
5,
7,
9,
10
],
"totalGoals": 24
}
]
}
I am using Groovy for this project, but I guess it's just the general JSON postgres syntax I am having problems with.
You're right, that's a problem with SQL syntax. Correct you query:
select * from json_test where content->'playersContainer'->'series' #> '[{"id":"1"}]';
Full example:
CREATE TABLE json_test (
content jsonb
);
insert into json_test(content) VALUES ('{"id": "1",
"team": {
"id": "123",
"name": "Shire Soldiers"
},
"playersContainer": {
"series": [
{
"id": "1",
"name": "Nick",
"teamName": "Shire Soldiers",
"ratings": [
1,
5,
6,
9
],
"assists": 17,
"manOfTheMatches": 20,
"cleanSheets": 1,
"data": [
3,
2,
3,
5,
6
],
"totalGoals": 19
},
{
"id": "2",
"name": "Pasty",
"teamName": "Shire Soldiers",
"ratings": [
6,
8,
9,
10
],
"assists": 25,
"manOfTheMatches": 32,
"cleanSheets": 2,
"data": [
3,
5,
7,
9,
10
],
"totalGoals": 24
}
]
}}');
select * from json_test where content->'playersContainer'->'series' #> '[{"id":"1"}]';
About #> operator. This question might be also useful.
May be it could help: Into the sql statement, I added this 'cast' where I have the json field:
INSERT INTO map_file(type, data)
VALUES (?, CAST(? AS json))
RETURNING id
the datatype of 'data' into map_file table is: json

reformating cakephp find threaded

My goal is to use a tree object to store invoices. The issue I'm running into is that it always puts a "Invoice" model wrapper around each subsequent child. I tried just getting the results and using the Set class to clean up the redundant "Invoice", "children" but I couldn't figure out how to get it to work. I'm using this in an API so basically what I want to be able to do is move up and down the array without having to constantly do invoice.children.invoice.children
In my controller I have:
$results = $this->Invoice->find('threaded', array(
'order' => array('lft ASC') // or array('id ASC')
));
$this->set(array(
'results' => $results,
'_serialize' => 'results'
));
What I'm getting is:
{
"success": true,
"data": [
{
"id": 1,
"parent_id": null,
"lft": 1,
"rght": 30,
"name": "Invoices",
"children": [
{
"Invoice": {
"id": 2,
"parent_id": 1,
"lft": 2,
"rght": 15,
"text": "invoice 001"
},
"children": [
{
"Invoice": {
"id": 3,
"parent_id": 2,
"lft": 3,
"rght": 8,
"text": "invoice_item"
},
"children": [
{
"Invoice": {
"id": 4,
"parent_id": 3,
"lft": 4,
"rght": 5,
"text": "invoice_sub_item"
},
"children": []
},
{
"Invoice": {
"id": 5,
"parent_id": 3,
"lft": 6,
"rght": 7,
"text": "subitem#2"
},
"children": []
}
]
}
]
}
]
}
]
}
Ideally I'd like to have
invoices.invoice.text = "invoice 001"
and
invoices.invoice.invoice_item[0].text = "invoice_item"
Obviously I'll need to add/take away from the array and resubmit with changes. Is this possible or am I just making things harder on myself?