2

I have data stored in a Postgres 12 table as jsonb, the structure of the jsonb has an array inside an array.

How do i get the values from the nested array? I can get the values from the first level array but not the second level array.

This is a simplified example of the json

{
    "id": 1,
    "external_order_id": {
        "id": "2"
    },
    "customer": {
        "external_customer_id": {
            "id": "3"
        }
    },
    "line_items": [
        {
            "sku": "SKU-1",
            "properties": [
                {
                    "name": "colour",
                    "value": "red"
                },
                {
                    "name": "size",
                    "value": "large"
                }
            ],
            "external_product_id": {
                "id": "4"
            },
            "external_variant_id": {
                "id": "5"
            }
        },
        {
            "sku": "SKU-2",
            "properties": [
                {
                    "name": "colour",
                    "value": "black"
                },
                {
                    "name": "size",
                    "value": "small"
                }
            ],
            "external_product_id": {
                "id": "8"
            },
            "external_variant_id": {
                "id": "9"
            }
        }
    ]
}

using jsonb_to_record and jsonb_to_recordset with LATERAL and CROSS JOIN LATERAL, i am able to get the values from the nodes and the first level array

WITH data(content) AS ( VALUES
  ('{
    "id": 1,
         "external_order_id": {
        "id": "2"
    },
    "customer": {
        
        "external_customer_id": {
            "id": "3"
        }
    },
    "line_items": [
        {
            "sku": "SKU-1",
            "properties": [
                {
                    "name": "colour",
                    "value": "red"
                },
                {
                    "name": "size",
                    "value": "large"
                }
            ],
            "external_product_id": {
                "id": "4"
            },
            "external_variant_id": {
                "id": "5"
            }
        },
                {
            "sku": "SKU-2",
            "properties": [
                {
                    "name": "colour",
                    "value": "black"
                },
                {
                    "name": "size",
                    "value": "small"
                }
            ],
            "external_product_id": {
                "id": "8"
            },
            "external_variant_id": {
                "id": "9"
            }
        }
    ]
   
}'::jsonb)
)
select ord.*
,ext.id as external_order_id
,cus.id as external_customer_id
,line_items.*

FROM data,
jsonb_to_record(content) as ord(id int),
LATERAL jsonb_to_record(content->'external_order_id') as ext(id text),
LATERAL jsonb_to_record(content#>'{customer, external_customer_id}') as cus(id text)
CROSS JOIN LATERAL jsonb_to_recordset(content->'line_items') line_items(sku text)

This is the result so far

| id | external_order_id | external_customer_id | sku   |
|----|-------------------|----------------------|-------|
| 1  | 2                 | 3                    | SKU-1 |
| 1  | 2                 | 3                    | SKU-2 |

what i want to achieve is. ideally this would be achieved without knowing the values of the property names

| id | external_order_id | external_customer_id | sku   | external_product_id | external_variant_id | property_name | property_value |
|----|-------------------|----------------------|-------|---------------------|---------------------|---------------|----------------|
| 1  | 2                 | 3                    | SKU-1 | 4                   | 5                   | colour        | red            |
| 1  | 2                 | 3                    | SKU-1 | 4                   | 5                   | size          | large          |
| 1  | 2                 | 3                    | SKU-2 | 8                   | 9                   | colour        | black          |
| 1  | 2                 | 3                    | SKU-2 | 8                   | 9                   | size          | small          |

dbfiddle

1 Answer 1

3
WITH data(content) AS ( VALUES
  ('{
    "id": 1,
         "external_order_id": {
        "id": "2"
    },
    "customer": {

        "external_customer_id": {
            "id": "3"
        }
    },
    "line_items": [
        {
            "sku": "SKU-1",
            "properties": [
                {
                    "name": "colour",
                    "value": "red"
                },
                {
                    "name": "size",
                    "value": "large"
                }
            ],
            "external_product_id": {
                "id": "4"
            },
            "external_variant_id": {
                "id": "5"
            }
        },
                {
            "sku": "SKU-2",
            "properties": [
                {
                    "name": "colour",
                    "value": "black"
                },
                {
                    "name": "size",
                    "value": "small"
                }
            ],
            "external_product_id": {
                "id": "8"
            },
            "external_variant_id": {
                "id": "9"
            }
        }
    ]

}'::jsonb)
)
select ord.*
,ext.id as external_order_id
,cus.id as external_customer_id
,line_items.sku
,line_items.external_product_id->>'id' as external_product_id
,line_items.external_variant_id->>'id' as external_variant_id
,props.*
FROM data,
jsonb_to_record(content) as ord(id int),
LATERAL jsonb_to_record(content->'external_order_id') as ext(id text),
LATERAL jsonb_to_record(content#>'{customer, external_customer_id}') as cus(id text)
CROSS JOIN LATERAL jsonb_to_recordset(content->'line_items') line_items(sku text, properties jsonb, external_product_id jsonb, external_variant_id jsonb)
cross join LATERAL jsonb_to_recordset(line_items.properties) props(name text, value text)
Sign up to request clarification or add additional context in comments.

1 Comment

Perfect, thank you. i had found a post that suggested you could pass results down to the next lateral join, but i couldn't quite figure out the syntax. It looks so obvious once you see the answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.