PostgreSQL JSONB 函数的不同路径格式
Different path formats for PostgreSQL JSONB functions
我对 path 如何根据 PostgreSQL JSONB documentation 中的函数使用不同的格式感到困惑。
如果我有一个 PostgreSQL table foo 看起来像
pk
json_obj
0
{"values": [{"id": "a_b", "value": 5}, {"id": "c_d", "value": 6]}
1
{"values": [{"id": "c_d", "value": 7}, {"id": "e_f", "value": 8]}
为什么这个查询会给我这些结果?
SELECT json_obj, -- {"values": [{"id": "a_b", "value": 5}, {"id": "c_d", "value": 6]}
json_obj @? '$.values[*].id', -- true
json_obj #> '$.values[*].id', -- ERROR: malformed array literal
json_obj #> '{values, 0, id}', -- "a_b"
JSONB_SET(json_obj, '$.annotations[*].id', '"hi"') -- ERROR: malformed array literal
FROM foo;
具体来说,为什么 @?
支持 $.values[*].id
(在另一个 section 的那个页面上有描述)但 JSONB_SET
使用其他路径格式 {bar,3,baz}
?
最终,我想做但不知道如何做的是删除路径 [=14= 表示的所有 id
值中的非字母数字字符(例如本例中的下划线) ].
原因是右边的运算符有不同的数据类型。
SELECT oprname, oprright::regtype
FROM pg_operator
WHERE oprleft = 'jsonb'::regtype
AND oprname IN ('@?', '#>');
oprname | oprright
---------+----------
#> | text[]
@? | jsonpath
(2 rows)
同样,jsonb_set
的第二个参数是text[]
。
现在 '$.values[*].id'
是有效的 jsonpath
,但不是有效的 text[]
文字。
感谢您就数据类型不同的原因提供答案和评论。
我想post我是如何解决我的问题的:
Ultimately, what I would like to do and don't know how, is to remove
non-alphanumeric characters (e.g. underscores in this example) in all
id
values represented by the path $.values[*].id
.
WITH unnested AS (
SELECT f.pk, JSONB_ARRAY_ELEMENTS(f.json_obj -> 'values') AS value
FROM foo f
),
updated_values AS (
SELECT un.pk, JSONB_SET(un.value, '{id}', TO_JSONB(LOWER(REGEXP_REPLACE(un.value ->> 'id', '[^a-zA-Z0-9]', '', 'g'))), FALSE) AS new_value
FROM unnested un
WHERE value -> 'id' IS NOT NULL -- Had some values that didn't have 'id' keys
)
UPDATE foo f2
SET json_obj = JSONB_SET(f2.json_obj, '{values}', (SELECT JSONB_AGG(uv.new_value) FROM updated_values uv WHERE uv.pk = f2.pk), FALSE)
WHERE JSONB_PATH_EXISTS(f2.json_obj, '$.values[*].id') -- Had some values that didn't have 'id' keys
我对 path 如何根据 PostgreSQL JSONB documentation 中的函数使用不同的格式感到困惑。
如果我有一个 PostgreSQL table foo 看起来像
pk | json_obj |
---|---|
0 | {"values": [{"id": "a_b", "value": 5}, {"id": "c_d", "value": 6]} |
1 | {"values": [{"id": "c_d", "value": 7}, {"id": "e_f", "value": 8]} |
为什么这个查询会给我这些结果?
SELECT json_obj, -- {"values": [{"id": "a_b", "value": 5}, {"id": "c_d", "value": 6]}
json_obj @? '$.values[*].id', -- true
json_obj #> '$.values[*].id', -- ERROR: malformed array literal
json_obj #> '{values, 0, id}', -- "a_b"
JSONB_SET(json_obj, '$.annotations[*].id', '"hi"') -- ERROR: malformed array literal
FROM foo;
具体来说,为什么 @?
支持 $.values[*].id
(在另一个 section 的那个页面上有描述)但 JSONB_SET
使用其他路径格式 {bar,3,baz}
?
最终,我想做但不知道如何做的是删除路径 [=14= 表示的所有 id
值中的非字母数字字符(例如本例中的下划线) ].
原因是右边的运算符有不同的数据类型。
SELECT oprname, oprright::regtype
FROM pg_operator
WHERE oprleft = 'jsonb'::regtype
AND oprname IN ('@?', '#>');
oprname | oprright
---------+----------
#> | text[]
@? | jsonpath
(2 rows)
同样,jsonb_set
的第二个参数是text[]
。
现在 '$.values[*].id'
是有效的 jsonpath
,但不是有效的 text[]
文字。
感谢您就数据类型不同的原因提供答案和评论。
我想post我是如何解决我的问题的:
Ultimately, what I would like to do and don't know how, is to remove non-alphanumeric characters (e.g. underscores in this example) in all
id
values represented by the path$.values[*].id
.
WITH unnested AS (
SELECT f.pk, JSONB_ARRAY_ELEMENTS(f.json_obj -> 'values') AS value
FROM foo f
),
updated_values AS (
SELECT un.pk, JSONB_SET(un.value, '{id}', TO_JSONB(LOWER(REGEXP_REPLACE(un.value ->> 'id', '[^a-zA-Z0-9]', '', 'g'))), FALSE) AS new_value
FROM unnested un
WHERE value -> 'id' IS NOT NULL -- Had some values that didn't have 'id' keys
)
UPDATE foo f2
SET json_obj = JSONB_SET(f2.json_obj, '{values}', (SELECT JSONB_AGG(uv.new_value) FROM updated_values uv WHERE uv.pk = f2.pk), FALSE)
WHERE JSONB_PATH_EXISTS(f2.json_obj, '$.values[*].id') -- Had some values that didn't have 'id' keys