I have a request to make the below JSON format and it seems very complex to me, I tried with the below solution but facing 2 issues
1.Sub child items under the child items seems not to be working.
Also if i have multiple products in one order , I would like to have that comes under this tags "lineItems" , But instead with the solution i have worked upon, If there are multiple products each is generating a separate JSON row, I need one JSON row per order.
It will be of very help if anyone of can give shred some light here.
Sample JSON String to be constructed.
{
"order_id": "string",
"createdAt": 0,
"orderNumber": "string",
"tags": [
"string"
],
"lineItems": [
{
"line_id": "string",
"productName": "string",
"quantity": 0,
"productTags": [
"string"
],
"discounts": [
{
"title": "string",
"voucherCode": "string",
"discountAmount": 0.1
}
],
"taxes": [
{
"tactitle": "string",
"taxRate": 0.1,
"taxAmount": 0.1
}
],
"totalAmountBeforeTaxesAndDiscounts": 0.1,
"totalAmountAfterTaxesAndDiscounts": 0.1
}
],
"shipping": {
"city": "string",
"zipOrPostalCode": "string",
"providerDescriptor": "string",
"shippingTotalAmountBeforeTaxAndDiscounts": 0.1,
"discounts": [
{
"title": "string",
"voucherCode": "string",
"discountAmount": 0.1
}
],
"taxes": [
{
"title": "string",
"taxRate": 0.1,
"taxAmount": 0.1
}
],
"shippingTotalAmountAfterTaxAndDiscounts": 0.1
},
"transactionCosts": 0.1,
"customer": {
"id": "string",
"email": "string",
"tags": [
"string"
]
},
"optional": {
"googleAnalyticsTransactionId": "string",
"orderSourceName": "string",
"orderChannelName": "string",
"orderPlatformName": "string"
}
}
The solution I have tried is below.
With orders as
(
SELECT "order_id",
"createdAt",
"orderNumber",
STRING_AGG(tags,',') as tags
FROM orders o
)
,lineItems as
(
SELECT "line_id",
order_id
"productName",
"quantity",
STRING_AGG(productTags,',') as "productTags",
"vouchertitle",
"voucherCode",
"discountAmount",
"taxtitle",
"taxRate",
"taxAmount",
"totalAmountBeforeTaxesAndDiscounts",
"totalAmountAfterTaxesAndDiscounts"
FROM items
)
,shipments as
(
SELECT order_id,
"city",
"zipOrPostalCode",
"providerDescriptor",
"shippingTotalAmountBeforeTaxAndDiscounts",
"title",
"voucherCode",
"discountAmount",
"taxtitle",
"taxRate",
"taxAmount",
"shippingTotalAmountAfterTaxAndDiscounts"
FROM shipments s
INNER JOIN orders o ON s.order_id=o.id
)
,customer AS
(
SELECT
order_id,
"customer_id",
"email"
STRING_AGG("customer_tags") as tags
FROM customers c
)
, optional AS
(
SELECT order_id,
"googleAnalyticsTransactionId",
"source",
"channel",
"platform"
FROM analytics
)
, base as (
select
cm.*,i as lineItems
, s as shipment
, c as customer
, ga as "optionalIdentifiers"
from
orders cm
LEFT JOIN lineItems i ON cm.order_id = i.order_id
LEFT JOIN shipments s ON cm.order_id=s.order_id
LEFT JOIN customer c ON cm."order_id"=c.order_id
LEFT JOIN optional ga ON cm."order_id"=ga.order_id
)
select row_to_json(c) as "data" from base c
Sample Input
create temp table orders(order_id int,"createdAt" date,"orderNumber" text,tags text);
INSERT INTO orders(order_id,"createdAt","orderNumber",tags)
VALUES (1,'2022-12-09' , '10001', 'no tags'),
(2,'2022-12-10' , '19999', 'tag1,tags 2');
create temp table lineItems(line_id int,order_id int,"productName" text,"quantity" int,
"productTags" text,"vouchertitle" text,"voucherCode" text,"discountAmount" real,
"taxtitle" text,"taxRate" real,"taxAmount" real,"totalAmountBeforeTaxesAndDiscounts" real,
"totalAmountAfterTaxesAndDiscounts" real);
INSERT INTO lineItems(line_id ,order_id ,"productName" ,"quantity" ,
"productTags" ,"vouchertitle" ,"voucherCode" ,"discountAmount" ,
"taxtitle" ,"taxRate" ,"taxAmount" ,"totalAmountBeforeTaxesAndDiscounts" ,
"totalAmountAfterTaxesAndDiscounts" )
VALUES (0,1,'Vitamin D',100,'Bio','Xmas campaign','XMAS001',1000,'TAX 10%',10,500,15000,14000),
(2,1,'Vitamin C',50,'No Tags','Xmas campaign','XMAS001',500,'TAX 7%',7,33,1900,1400),
(11,2,'Vitamin C',50,'No Tags','Xmas campaign','XMAS002',100,'TAX 7%',7,55,2500,2400)
;
create temp table shipments(order_id int,"city" text,"zipOrPostalCode" text,"providerDescriptor" text,
"shippingTotalAmountBeforeTaxAndDiscounts" real,"title" text,"voucherCode" text,"discountAmount" real,
"taxtitle" text,"taxRate" real,"taxAmount" real,"shippingTotalAmountAfterTaxAndDiscounts" real);
INSERT INTO shipments(order_id ,"city" ,"zipOrPostalCode" ,"providerDescriptor" ,
"shippingTotalAmountBeforeTaxAndDiscounts" ,"title" ,"voucherCode" ,"discountAmount" ,
"taxtitle" ,"taxRate" ,"taxAmount" ,"shippingTotalAmountAfterTaxAndDiscounts" )
VALUES (1,'Berlin','100203','DHL','100','Shipper','XMAS001',1000,'TAX 10%',10,500,1000),
(2,'Milan','122203','Hermes','100','Shipp_001','XMAS002',1000,'TAX 7%',7,500,1000);
create temp table customer( order_id int,"customer_id" int,"email" text,"customer_tags" text);
INSERT INTO customer(order_id ,"customer_id" ,"email" ,"customer_tags" )
VALUES (1,1900,'xxxx#gmail.com','new')
, (2,2000,'yyyy#gmail.com','return');
create temp table optional( order_id int,"googleAnalyticsTransactionId" int,"source" text,"channel" text,"platform" text);
INSERT INTO optional(order_id ,"googleAnalyticsTransactionId" ,"source" ,"channel" ,platform)
VALUES (1,'9990001','facebook','paid marketing','mobile')
,(2,'7770001','gppgle','direct','mobile');
Sample Expected Output
The output JSON is formulated with only one entry,With order id=1
{
"order_id": "1",
"createdAt": "2022-12-09",
"orderNumber": '10001',
"tags": ['no tags' ],
"lineItems": [
{
"line_id": "0",
"productName": 'Vitamin D',
"quantity": 100,
"productTags": [ 'Bio'],
"discounts": [
{
"title": 'Xmas campaign',
"voucherCode": 'XMAS001',
"discountAmount": 1000
}
],
"taxes": [
{
"tactitle": 'TAX 10%',
"taxRate": 10,
"taxAmount": 500
}
],
"totalAmountBeforeTaxesAndDiscounts": 15000,
"totalAmountAfterTaxesAndDiscounts": 14000
},
{
"line_id": "2",
"productName": 'Vitamin C',
"quantity": 50,
"productTags": [ 'No Tags'],
"discounts": [
{
"title": 'Xmas campaign',
"voucherCode": 'XMAS001',
"discountAmount": 500
}
],
"taxes": [
{
"tactitle": 'TAX 7%',
"taxRate": 7,
"taxAmount": 33
}
],
"totalAmountBeforeTaxesAndDiscounts": 1900,
"totalAmountAfterTaxesAndDiscounts": 1400
}
],
"shipping": {
"city": 'Berlin',
"zipOrPostalCode": "100203",
"providerDescriptor": "DHL",
"shippingTotalAmountBeforeTaxAndDiscounts": 100,
"discounts": [
{
"title": "TAX 10%",
"voucherCode": 'XMAS001',
"discountAmount": 500
}
],
"taxes": [
{
"title": "XMAS001",
"taxRate": 10,
"taxAmount": 500
}
],
"shippingTotalAmountAfterTaxAndDiscounts": 1000
},
"transactionCosts": 0.1,
"customer": {
"id": "1900",
"email": "xxxx#gmail.com",
"tags": [
"new"
]
},
"optional": {
"googleAnalyticsTransactionId": "9990001",
"orderSourceName": "facebook",
"orderChannelName": "paid marketing",
"orderPlatformName": "mobile"
}
}
I have written a part for you, which by looking at the code, you can understand how the functions work. I think you can write the continuation of the same by looking at this logic. If you have a problem, you can tell me, I will write it in full, I just didn't write all the names of the fields, so I'm sorry.
SQL query:
select json_build_object('lineItems',
json_agg(json_build_object(
'line_id', lt.line_id,
'productName', lt."productName",
'quantity', lt.quantity,
'discounts',
json_build_array(json_build_object(
'title', lt.vouchertitle,
'voucherCode', lt."voucherCode",
'discountAmount', lt."discountAmount")),
'taxes',
json_build_array(json_build_object(
'tactitle', lt.taxtitle,
'taxRate', lt."taxRate",
'taxAmount', lt."taxAmount")),
'totalAmountBeforeTaxesAndDiscounts', lt."totalAmountBeforeTaxesAndDiscounts",
'totalAmountAfterTaxesAndDiscounts', lt."totalAmountAfterTaxesAndDiscounts"))
)
from orders o
inner join lineitems lt on o.order_id = lt.order_id
inner join shipments sp on o.order_id = sp.order_id
where o.order_id = 1
And result:
{
"lineItems": [
{
"line_id": 0,
"productName": "Vitamin D",
"quantity": 100,
"discounts": [
{
"title": "Xmas campaign",
"voucherCode": "XMAS001",
"discountAmount": 1000
}
],
"taxes": [
{
"tactitle": "TAX 10%",
"taxRate": 10,
"taxAmount": 500
}
],
"totalAmountBeforeTaxesAndDiscounts": 15000,
"totalAmountAfterTaxesAndDiscounts": 14000
},
{
"line_id": 2,
"productName": "Vitamin C",
"quantity": 50,
"discounts": [
{
"title": "Xmas campaign",
"voucherCode": "XMAS001",
"discountAmount": 500
}
],
"taxes": [
{
"tactitle": "TAX 7%",
"taxRate": 7,
"taxAmount": 33
}
],
"totalAmountBeforeTaxesAndDiscounts": 1900,
"totalAmountAfterTaxesAndDiscounts": 1400
}
]
}
a have a simple table of purchases consisting of id and jsonb column, like this:
CREATE TABLE purchase (id SERIAL, products JSONB)
Then and index:
CREATE INDEX idx_purchase_products ON purchase USING GIN (products);
The sample data are like this:
INSERT INTO purchase VALUES (
1, jsonb('[
{
"country": 1,
"type": 1,
"size": 10,
"color": 3
}
]')
),
(
2, jsonb('[
{
"country": 1,
"type": 1,
"size": 10,
"color": 3
},
{
"country": 1,
"type": 2,
"size": 12,
"color": 4
},
{
"country": 2,
"type": 1,
"size": 12,
"color": 3
}
]')
),
(
3, jsonb('[
{
"country": 1,
"type": 1,
"size": 10,
"color": 3
}
]')
),
(
4, jsonb('[
{
"country": 1,
"type": 1,
"size": 10,
"color": 3
},
{
"country": 1,
"type": 2,
"size": 12,
"color": 4
},
{
"country": 2,
"type": 1,
"size": 12,
"color": 3
}
]')
);
And some scenarios of searching:
SELECT *
FROM purchase
WHERE products #> '[{"country": 1}]'
SELECT *
FROM purchase
WHERE products #> '[{"country": 1, "type": 1}]'
SELECT *
FROM purchase
WHERE products #> '[{"size": 12}]'
SELECT *
FROM purchase
WHERE products #> '[{"size": 12, "color": 4}]'
It is expected, that the customer could search for combinations:
country,
country + type
country + type + size
country + type + size + color
country + size
size + color
type + color
etc.
And there is a big chance, the list of 4 field (country, type, size, color) will grow in future to 7-10.
And of course we want also search combinations like this:
.. WHERE products #> '[{"country": 1}]' OR products #> '[{"color": 4}]' OR products #> '[{"type": 1, "size": 10}]'
Estimated size of the table purchase is 9-12 millions rows (depending on season).
Any idea how to implement the indexes to get the query result as fast as possible?