多个 key/value 对的 PostgresQL 嵌套 jsonb 查询
PostgresSQL nested jsonb query for multiple key/value pairs
开始使用 JSONB 数据类型,希望有人能帮助我。
我有一个 table (properties) 有两列(id 作为主键和 数据 作为 jsonb)。
数据结构为:
{
"ProductType": "ABC",
"ProductName": "XYZ",
"attributes": [
{
"name": "Color",
"type": "STRING",
"value": "Silver"
},
{
"name": "Case",
"type": "STRING",
"value": "Shells"
},
...
]
}
我想获取属性具有特定值的所有行,即 return Case = 'Shells' and/or 的所有行颜色 = 'Red'.
我尝试了以下方法,但无法应用两个条件,例如 Case = 'Shells' 和 Color = 'Silver'。
当单个属性的名称和值匹配条件时,我可以获得行,但我不知道如何让它对多个属性起作用。
编辑 1:
我能够使用以下查询获得结果:
WITH properties AS (
select *
from (
values
(1, '{"ProductType": "ABC","ProductName": "XYZ","attributes": [{"name": "Color","type": "STRING","value": "Silver"},{"name": "Case","type": "STRING","value": "Shells"}]}'::jsonb),
(2, '{"ProductType": "ABC","ProductName": "XYZ","attributes": [{"name": "Color","type": "STRING","value": "Red"},{"name": "Case","type": "STRING","value": "Shells"}]}'::jsonb)
) s(id, data)
)
select
*
from (
SELECT
id,
jsonb_object_agg(attr ->> 'name', attr -> 'value') as aggr
FROM properties m,
jsonb_array_elements(data -> 'attributes') as attr
GROUP BY id
) a
where aggr ->> 'Color' = 'Red' and aggr ->> 'Case' LIKE 'Sh%'
我可能有数百万条这样的记录,所以我想我现在唯一关心的是这是否有效,如果无效,是否有更好的方法?
SELECT
id
FROM properties m,
jsonb_array_elements(data -> 'attributes') as attr
GROUP BY id
HAVING jsonb_object_agg(attr ->> 'name', attr -> 'value') @> '{"Color":"Silver", "Case":"Shells"}'::jsonb
问题是,jsonb_array_elements()
将两个相关值移动到不同的记录中。但是,此调用是获取值所必需的。因此,您需要在能够读取它们之后重新聚合这些值。这将使以相关方式检查它们成为可能。
这可以通过使用 jsonb_object_agg()
聚合函数来实现。这里的技巧是我们创建一个具有 "name":"value"
等属性的对象。因此,有了它,我们可以使用 @>
运算符轻松检查是否所有必需的属性都在 JSON 对象中。
关于“编辑 1”
你可以这样做:
SELECT
*
FROM (
SELECT
id,
jsonb_object_agg(attr ->> 'name', attr -> 'value') as obj
FROM properties m,
jsonb_array_elements(data -> 'attributes') as attr
GROUP BY id
) s
WHERE obj ->> 'Color' = 'Silver'
AND obj ->> 'Case' LIKE 'Sh%'
- 如上所述为所有 JSONs
创建新的 JSON 结构
- 之后过滤这个结果。
或者,您可以根据需要在 HAVING
子句中使用 jsonb_object_agg()
。我想您需要检查哪种方式在您的情况下性能更高:
SELECT
id
FROM properties m,
jsonb_array_elements(data -> 'attributes') as attr
GROUP BY id
HAVING
jsonb_object_agg(attr ->> 'name', attr -> 'value') ->> 'Color' = 'Silver'
AND
jsonb_object_agg(attr ->> 'name', attr -> 'value') ->> 'Case' LIKE 'Sh%'
开始使用 JSONB 数据类型,希望有人能帮助我。
我有一个 table (properties) 有两列(id 作为主键和 数据 作为 jsonb)。 数据结构为:
{
"ProductType": "ABC",
"ProductName": "XYZ",
"attributes": [
{
"name": "Color",
"type": "STRING",
"value": "Silver"
},
{
"name": "Case",
"type": "STRING",
"value": "Shells"
},
...
]
}
我想获取属性具有特定值的所有行,即 return Case = 'Shells' and/or 的所有行颜色 = 'Red'.
我尝试了以下方法,但无法应用两个条件,例如 Case = 'Shells' 和 Color = 'Silver'。 当单个属性的名称和值匹配条件时,我可以获得行,但我不知道如何让它对多个属性起作用。
编辑 1: 我能够使用以下查询获得结果:
WITH properties AS (
select *
from (
values
(1, '{"ProductType": "ABC","ProductName": "XYZ","attributes": [{"name": "Color","type": "STRING","value": "Silver"},{"name": "Case","type": "STRING","value": "Shells"}]}'::jsonb),
(2, '{"ProductType": "ABC","ProductName": "XYZ","attributes": [{"name": "Color","type": "STRING","value": "Red"},{"name": "Case","type": "STRING","value": "Shells"}]}'::jsonb)
) s(id, data)
)
select
*
from (
SELECT
id,
jsonb_object_agg(attr ->> 'name', attr -> 'value') as aggr
FROM properties m,
jsonb_array_elements(data -> 'attributes') as attr
GROUP BY id
) a
where aggr ->> 'Color' = 'Red' and aggr ->> 'Case' LIKE 'Sh%'
我可能有数百万条这样的记录,所以我想我现在唯一关心的是这是否有效,如果无效,是否有更好的方法?
SELECT
id
FROM properties m,
jsonb_array_elements(data -> 'attributes') as attr
GROUP BY id
HAVING jsonb_object_agg(attr ->> 'name', attr -> 'value') @> '{"Color":"Silver", "Case":"Shells"}'::jsonb
问题是,jsonb_array_elements()
将两个相关值移动到不同的记录中。但是,此调用是获取值所必需的。因此,您需要在能够读取它们之后重新聚合这些值。这将使以相关方式检查它们成为可能。
这可以通过使用 jsonb_object_agg()
聚合函数来实现。这里的技巧是我们创建一个具有 "name":"value"
等属性的对象。因此,有了它,我们可以使用 @>
运算符轻松检查是否所有必需的属性都在 JSON 对象中。
关于“编辑 1”
你可以这样做:
SELECT
*
FROM (
SELECT
id,
jsonb_object_agg(attr ->> 'name', attr -> 'value') as obj
FROM properties m,
jsonb_array_elements(data -> 'attributes') as attr
GROUP BY id
) s
WHERE obj ->> 'Color' = 'Silver'
AND obj ->> 'Case' LIKE 'Sh%'
- 如上所述为所有 JSONs 创建新的 JSON 结构
- 之后过滤这个结果。
或者,您可以根据需要在 HAVING
子句中使用 jsonb_object_agg()
。我想您需要检查哪种方式在您的情况下性能更高:
SELECT
id
FROM properties m,
jsonb_array_elements(data -> 'attributes') as attr
GROUP BY id
HAVING
jsonb_object_agg(attr ->> 'name', attr -> 'value') ->> 'Color' = 'Silver'
AND
jsonb_object_agg(attr ->> 'name', attr -> 'value') ->> 'Case' LIKE 'Sh%'