如何通过深度嵌套的 jsonb 数据创建带有顺序的查询?

How to create a query with order by deeply nested jsonb data?

我有一个包含 4 列的 table availabilityproductcodecurrencybookableitemssummary.

bookableitems 是 JSONB。

我需要 select 所有包含 currency = 'USD'productOptionCode = 'TG11' 以及 ORDER BY [recommendedRetailPrice of ageBand = 'CHILD'] DESC 的记录。

currencyproductOptionCode 的选择很简单:

SELECT *
FROM availability
WHERE currency = 'USD' AND bookableitems @> '[{"productOptionCode": "TG11"}]'

但我找不到如何按如此深的数据排序的示例(尤其是如何执行 4 个嵌套循环,bookableitemsseasonspricingRecordspricingDetails 为了找到 ageBand = 'CHILD').

一行示例:

"productcode": "46258P1", 
"currency": "USD", 
"bookableitems": [
    {
        "seasons": [
            {
                "startDate": "2019-08-12",
                "pricingRecords": [
                    {
                        "daysOfWeek": ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"],
                        "timedEntries": [{"startTime": "20:30"}], 
                        "pricingDetails": [
                            {
                                "price": {
                                    "original": {
                                        "bookingFee": 8.69,
                                        "partnerNetPrice": 115.87,
                                        "partnerTotalPrice": 124.56,
                                        "recommendedRetailPrice": 139.49
                                    }
                                }, 

                                "ageBand": "CHILD",
                                "minTravelers": 1,
                                "pricingPackageType": "PER_PERSON"
                            },
                            
                            {
                                "price": {
                                    "original": {
                                        "bookingFee": 11.57,
                                        "partnerNetPrice": 154.21,
                                        "partnerTotalPrice": 165.78,
                                        "recommendedRetailPrice": 185.65
                                    }
                                }, 

                                "ageBand": "ADULT",
                                "minTravelers": 1,
                                "pricingPackageType": "PER_PERSON"
                            }
                        ]
                    }
                ]
            }
        ],

        "productOptionCode": "TG11"
    },

    {
        "seasons": [
            {
                "startDate": "2019-08-12",
                "pricingRecords": [
                    {
                        "daysOfWeek": ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"],
                        "timedEntries": [{"startTime": "20:30"}],
                        "pricingDetails": [
                            {
                                "price": {
                                    "original": {
                                        "bookingFee": 0.0, 
                                        "partnerNetPrice": 0.0, 
                                        "partnerTotalPrice": 0.0, 
                                        "recommendedRetailPrice": 0.0
                                    }
                                }, 

                                "ageBand": "INFANT", 
                                "minTravelers": 1, 
                                "pricingPackageType": "PER_PERSON"
                            },

                            {
                                "price": {
                                    "original": {
                                        "bookingFee": 8.95, 
                                        "partnerNetPrice": 119.28, 
                                        "partnerTotalPrice": 128.23, 
                                        "recommendedRetailPrice": 143.59
                                    }
                                },

                                "ageBand": "ADULT",
                                "minTravelers": 1,
                                "pricingPackageType": "PER_PERSON"
                            }
                        ]
                    }
                ]
            }
        ], 

        "productOptionCode": "TG1"
    }
], 

"summary": {"fromPrice": 185.65}

PostgreSQL v13.

有人可以告诉我正确的查询吗?

在对数据进行操作时,没有 PostgreSQL 索引会同时直接满足所有这些要求,除非我们假设 'TG11' 是硬编码的而不是可变参数(这似乎不太可能)。

这里是查询:

SELECT *, jsonb_path_query(a.bookableitems, '$[*].seasons[*].pricingRecords[*].pricingDetails[*] ? (@.ageBand == "CHILD")') -> 'price' -> 'original' -> 'recommendedRetailPrice' AS retailPrice
FROM availability as a
WHERE currency = 'USD' AND bookableitems @> '[{"productOptionCode": "TG11"}]'
ORDER BY retailPrice DESC;

这个请求jsonb_path_query(a.bookableitems, '$[*].seasons[*].pricingRecords[*].pricingDetails[*] ? (@.ageBand == "CHILD")')returns这个对象:

{
    "price": {
        "original": {
            "bookingFee": 8.69,
            "partnerNetPrice": 115.87,
            "partnerTotalPrice": 124.56,
            "recommendedRetailPrice": 139.49
        }
    }, 

    "ageBand": "CHILD",
    "minTravelers": 1,
    "pricingPackageType": "PER_PERSON"
}

然后 -> 'price' -> 'original' -> 'recommendedRetailPrice' AS retailPrice 简单地将 recommendedRetailPrice 提取为 retailPrice 以用于 ORDER BY 部分。

如果有人需要检查“CHILD”是否存在,只需添加:

AND jsonb_path_exists(a.bookableitems, '$[*].seasons[*].pricingRecords[*].pricingDetails[*] ? (@.ageBand == "CHILD")')

在 WHERE 部分内。

This Postgresql docs page helped and this article.