Query JSON in Postgres - json

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

Related

Order Only Nested Model Data Sequelize

I am trying to order only the nested include Scheme Model based on an integer column but it seems like the code is not working. Also, the data is being fetched from MYSQL bottom to up and shown as output.
sample code:
[err, products] = await to(
Product_Inventory_Mapping.findAll({
include: [
{
model: Product,
as: "product_details",
where: filterClause,
include: [
{
model: Unit,
as: "unit_details"
},
{
model: Brand,
as: "brand_details"
},
{
model: Category,
as: "category_details"
},
{
model: Sub_Brand,
as: "sub_brand_details"
},
{
model: Sub_Category,
as: "sub_category_details"
},
{
model: Brand_Company,
as: "brand_company_details"
},
{
model: Scheme,
as: "schemes",
attributes: [`moq`, 'discount', `description`],
order: [[{ model: Scheme, as: "schemes" }, "moq", "ASC"]],
where: {
status: 1
},
required: false
}
]
}
],
order: [
[{ model: Product, as: "product_details" }, "mrp", "ASC"]
],
where: {
user_id: aligned_distributors,
brand_company_id: filtered_brand_company,
count: {
[Op.gt]: 0
},
sp: {
[Op.gt]: 0
}
},
attributes: [
`product_id`,
"user_id",
"count",
"sp",
"occ",
"brand_company_id"
],
limit: limit,
offset: offset,
subQuery: false
}));
Here I want to order only the data inside the Scheme Model.
Sample response:
"products": [
{
"product_id": 115,
"user_id": 1003,
"count": 50,
"sp": 9.09,
"occ": 9.09,
"brand_company_id": 11,
"product_details": {
"id": 115,
"category_id": 2,
"sub_category_id": 12,
"brand_company_id": 11,
"brand_id": 24,
"sub_brand_id": 44,
"sku_code": null,
"min_order_qty": "27",
"description": "Nandini Butter Milk Tetra Pack, 200 Ml",
"unit_id": 4,
"weight": "200ml",
"mrp": "10.00",
"barcode": "",
"image_url": "https://xxxxxx.s3.ap-south-1.amazonaws.com/products/1565919229Unknown-min-5.jpg",
"created_at": "2019-08-12T13:44:01.000Z",
"updated_at": "2019-08-15T20:03:49.000Z",
"unit_details": {
"id": 4,
"name": "Pieces",
"created_at": null,
"updated_at": null
},
"brand_details": {
"id": 24,
"name": "Nandini Butter Milk",
"brand_company_id": 11,
"created_at": null,
"updated_at": null
},
"category_details": {
"id": 2,
"name": "Packaged Food",
"image_url": "https://zzzz.s3.ap-south-1.amazonaws.com/images/category/food-min.png",
"created_at": "2019-08-11T11:36:52.000Z",
"updated_at": "2019-08-11T11:36:52.000Z"
},
"sub_brand_details": {
"id": 44,
"name": "Nandini Butter Milk",
"brand_id": 24,
"created_at": null,
"updated_at": null
},
"sub_category_details": {
"id": 12,
"name": "Dairy products (Butter, Cheese etc)",
"category_id": 2,
"created_at": null,
"updated_at": null
},
"brand_company_details": {
"id": 11,
"name": "Karnataka Co-operative Milk Producers",
"image_url": "https://xxxxx.s3.ap-south-1.amazonaws.com/images/company/kmf_logo.jpg",
"created_at": "2019-08-12T13:10:18.000Z",
"updated_at": "2019-08-12T13:10:18.000Z"
},
"schemes": [
{
"moq": 30,
"discount": 1.5,
"description": "8 % offer"
},
{
"moq": 20,
"discount": 1,
"description": "20 % offer"
},
{
"moq": 40,
"discount": 2,
"description": "40 % offer"
}
]
}
}]
In the database, the Scheme data is saved as:
Scheme belongs to the Product via product_id. I want the Scheme array to be sorted by moq ASC so that the value comes in order of moq: 20 > 30 > 40.
AFAIK, an order clause in the included model doesn't work. But, you can make a reference to the included model in the main model. I think this should work if you combine your two order clauses into one:
Product_Inventory_Mapping.findAll({
include: [
..... lots of includes here ....
],
order: [
[{ model: Product, as: "product_details" }, "mrp", "ASC"],
[{ model: Scheme, as: "schemes" }, "moq", "ASC"]]
],
This will order by moq within mrp... you could remove the first field if you really want to sort ONLY by moq....

Laravel pagination json format

I am using laravel database pagination for an api. It gives the output as follows :
{
"current_page": 1,
"data": [
{
"id": 1,
"name": "Default"
},
{
"id": 2,
"name": "Default without Sidebar"
}
],
"first_page_url": "http://example.com/api/layouts?a=1",
"from": 1,
"last_page": 1,
"last_page_url": "http://example.com/api/layouts?a=1",
"next_page_url": null,
"path": "http://example.com/api/layouts",
"per_page": 10,
"prev_page_url": null,
"to": 2,
"total": 2
}
I don't want or need first_page_url, last_page_url, etc, so it should just be:
{
"current_page": 1,
"data": [
{
"id": 1,
"name": "Default"
},
{
"id": 2,
"name": "Default without Sidebar"
}
],
"from": 1,
"last_page": 1,
"to": 2,
"total": 2
}
So, Is there a way, to format the output json so that i can remove or hide some extra info which i don't need .
You can do something like this:
$except = ['first_page_url', 'last_page_url'];
return array_except(<YourModel>::paginate(...)->toArray(), $except);

Export mysql data to JSON in a nested and recursivelty way starting from a table?

I have seen several examples to export MySQL tables to JSON, however such examples export data in an aggregated way. For example, take a database where you have two tables "Invoice head" and "Invoice details". "Invoice details" is a child of "Invoice head".The data in JSON is usually represented like:
{
"invoice_head": [
{
"number": 1,
"cliente": "Carlos",
"date": "2016-12-12"
},
{
"number": 2,
"cliente": "Fernando",
"date": "2017-01-01"
}
],
"invoice_details": [
{
"headnumber": 1,
"lineno": 1,
"product": "Shoes",
"quantity": 2
},
{
"headnumber": 1,
"lineno": 2,
"product": "Socks",
"quantity": 1
},
{
"headnumber": 2,
"lineno": 1,
"product": "Laptop",
"quantity": 1
}
],
}
I need to export data in a nested way:
{
"invice_head": [
{
"number": 1,
"cliente": "Carlos",
"date": "2016-12-12",
"invice_details": [
{
"headnumber": 1,
"lineno": 1,
"product": "Shoes",
"quantity": 2
},
{
"headnumber": 1,
"lineno": 2,
"product": "Socks",
"quantity": 1
}
]
},
{
"number": 2,
"cliente": "Fernando",
"date": "2017-01-01"
"invice_details": [
{
"headnumber": 2,
"lineno": 1,
"product": "Laptop",
"quantity": 1
}
]
}
]
}
For this I guess one needs to start in a table and recursively go through its childs for each record.
Does anybody knows if there is anything that does it? I don't want to reinvent the wheel.

Querying JSONB using Postgres

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.

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?