skip to Main Content

`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.`

2

Answers


  1. 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.

    Login or Signup to reply.
  2. 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;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search