`How can I get SQL join query that the results in json format using postgres? I believe this can be done but I am struggling to figure it out.
Here is the SQL code to create tables and insert test data.
CREATE TABLE backend.product (
id Integer NOT NULL,
category text NOT NULL,
title text NOT NULL,
price money NOT NULL
);
CREATE TABLE backend.product_details (
id Integer NOT NULL,
type text NOT NULL,
description text NOT NULL
);
CREATE TABLE backend.shipping (
id Integer NOT NULL,
description text NOT NULL,
price money NOT NULL
);
INSERT INTO backend.product (id, category, title, price) VALUES (1, 'sweatshirts', 'hoodie', '$50.00');
INSERT INTO backend.product_details (id, type, description) VALUES (1, 'color', 'red');
INSERT INTO backend.product_details (id, type, description) VALUES (1, 'color', 'blue');
INSERT INTO backend.product_details (id, type, description) VALUES (1, 'color', 'green');
INSERT INTO backend.product_details (id, type, description) VALUES (1, 'size', 'small');
INSERT INTO backend.product_details (id, type, description) VALUES (1, 'size', 'large');
INSERT INTO backend.shipping (id, description, price) VALUES (1, 'standard box', '$17.05');
I ran this query:
SELECT p.id, p.category, p.title, p.price, s.description as shipping_box, s.price as shipping_cost, pd.type, pd.description AS choice
FROM backend.product p, backend.shipping s, backend.product_details pd
WHERE p.id = s.id
AND p.id = 1
AND p.id IN (
SELECT pd.id
FROM backend.product_details pd
WHERE pd.id = 1
GROUP BY pd.id, pd.type, pd.description
);
Results:
id | category | title | price | shipping_box | shipping_cost | type | choice |
---|---|---|---|---|---|---|---|
1 | sweatshirts | hoodie | $50.00 | standard box | $17.05 | color | red |
1 | sweatshirts | hoodie | $50.00 | standard box | $17.05 | color | blue |
1 | sweatshirts | hoodie | $50.00 | standard box | $17.05 | color | green |
1 | sweatshirts | hoodie | $50.00 | standard box | $17.05 | size | small |
1 | sweatshirts | hoodie | $50.00 | standard box | $17.05 | size | large |
I want the results in json format like this:
[
{
"id": 1,
"category": "sweatshirts",
"title": "hoodie",
"price": "$50.00",
"shipping": {
"box": "standard box",
"cost": "$17.05"
},
"choices": [ {
"color": [ "red", "blue", "green" ],
"size": [ "small", "large" ]
} ]
}
]
So the results will really be one row. Thank you for any help.`
CodePudding user response:
I suggest using json_build_object
for example
SELECT json_build_object('id',p.id,'category',p.category,'title', p.title,'price' p.price)
FROM backend.product p, backend.shipping s, backend.product_details pd
WHERE p.id = s.id
AND p.id = 1
AND p.id IN (
SELECT pd.id
FROM backend.product_details pd
WHERE pd.id = 1
GROUP BY pd.id, pd.type, pd.description
);
and also you can do nested objects, by nesting json_build_objects inside.
CodePudding user response:
Here is the demo with the details.
I started with the deepest json layers - "shipping"
and "choices"
and finally have built the whole json (note: added the jsonb_pretty()
for the last select
, remove it if necessary):
--build json object for "shipping" field
with shipping_data as (
select id, json_build_object('box', description, 'cost', price) as json
from shipping
),
--build json object for "choices" field
choices_data as (
--build json aggregated by product 'id' column
with details_data as (
--build json with "type" and "description" fields - grouped by product 'id' and 'type' columns
select id, json_build_object(type, json_agg(description)) as type_json
from product_details
group by id, type)
select id, json_agg(type_json) as json
from details_data
group by id
)
--build final json with all fields
select product.id,
jsonb_pretty(json_build_object('id', product.id, 'category', category, 'title', title, 'price', price,
'shipping', shipping_data.json,
'choices', choices_data.json)::jsonb
) as product_json
from product
join shipping_data on shipping_data.id = product.id
join choices_data on choices_data.id = product.id;