bob*_*obb 8 postgresql json json-path jsonb
使用:Postgres 14.2。
目标:获取表中所有不同国家/地区的列表。
该列address
是一种JSONB
列类型,包含一个结构如下的数组:
{
"address":[
{
"types":["route"],
"long_name":"20203 113B Ave",
"short_name":"20203 113B Ave"
},
{
"types":["locality","political"],
"long_name":"Maple Ridge",
"short_name":"Maple Ridge"
},
{
"types":["administrative_area_level_3","political"],
"long_name":"Maple Ridge",
"short_name":"Maple Ridge"
},
{
"types":["administrative_area_level_2","political"],
"long_name":"Greater Vancouver",
"short_name":"Greater Vancouver"
},
{
"types":["administrative_area_level_1","political"],
"long_name":"British Columbia",
"short_name":"BC"
},
{
"types":["country","political"],
"long_name":"Canada",
"short_name":"CA"
},
{
"types":["postal_code"],
"long_name":"V2X 0Z1",
"short_name":"V2X 0Z1"
}
]
}
Run Code Online (Sandbox Code Playgroud)
如何过滤这个对象数组,使其仅返回数组索引(如果包含)的值"long_name"
(例如) ?Canada
types
"country"
我正在尝试类似的事情,但显然,我只想返回国家/地区,而不是整个品牌。
SELECT * from brand
where address::text ilike ANY (ARRAY['%country%'::text]);
Run Code Online (Sandbox Code Playgroud)
此查询失败并显示:
Run Code Online (Sandbox Code Playgroud){ "address":[ { "types":["route"], "long_name":"20203 113B Ave", "short_name":"20203 113B Ave" }, { "types":["locality","political"], "long_name":"Maple Ridge", "short_name":"Maple Ridge" }, { "types":["administrative_area_level_3","political"], "long_name":"Maple Ridge", "short_name":"Maple Ridge" }, { "types":["administrative_area_level_2","political"], "long_name":"Greater Vancouver", "short_name":"Greater Vancouver" }, { "types":["administrative_area_level_1","political"], "long_name":"British Columbia", "short_name":"BC" }, { "types":["country","political"], "long_name":"Canada", "short_name":"CA" }, { "types":["postal_code"], "long_name":"V2X 0Z1", "short_name":"V2X 0Z1" } ] }
SELECT * from brand
where exists (
select from jsonb_array_elements(address) e
where (e ->> 'types')::text = 'country'
);
Run Code Online (Sandbox Code Playgroud)
显然,这在 JS 中是微不足道的:
address.filter((part) => part.types.includes('country'))[0].long_name
Run Code Online (Sandbox Code Playgroud)
但我需要我的数据库来处理它。出了什么问题?
Erw*_*ter 12
顾名思义,需要取消嵌套jsonb_array_elements()
JSON数组。但是,根据您的错误消息,至少一行包含顶层带有JSON对象的jsonb
值。(除数组之外的任何内容都会触发错误。)
测试类型并排除违规行:address
jsonb_typeof()
SELECT DISTINCT x.address ->> 'long_name' AS country_name
FROM (
SELECT jsonb_array_elements(b.address) AS address
FROM brand b
WHERE jsonb_typeof(b.address) = 'array' -- !!!
) x
WHERE x.address ->> 'types' ILIKE ANY (ARRAY['%country%'::text]);
Run Code Online (Sandbox Code Playgroud)
更短的等价物:
SELECT DISTINCT x.adr->>'long_name' AS country_name
FROM brand b, jsonb_array_elements(b.address) x(adr)
WHERE jsonb_typeof(b.address) = 'array'
AND (x.adr->>'types') ~* 'country';
Run Code Online (Sandbox Code Playgroud)
更短的等价物jsonb_path_query()
SELECT DISTINCT jsonb_path_query(address, '$[*] ? (@.types[*] == "country").long_name')
FROM brand;
Run Code Online (Sandbox Code Playgroud)
Postgres 12 中添加了SQL/JSON的原始功能。一开始有点令人困惑,但功能强大。甚至可以使用索引。看:
我相信您确实想测试该types
数组是否与“国家/地区”完全匹配(就像您的 JS 代码所建议的那样),比您的 SQL 查询更严格。
如果您没有预料到该错误,您可能需要仔细查看违规行......
SELECT * FROM brand
WHERE jsonb_typeof(address) IS DISTINCT FROM 'array';
Run Code Online (Sandbox Code Playgroud)
null
价值观很好。其余的则不然。
db<>在这里摆弄
归档时间: |
|
查看次数: |
17673 次 |
最近记录: |