简体   繁体   中英

Different path formats for PostgreSQL JSONB functions

I'm confused by how path uses different formats depending on the function in the PostgreSQL JSONB documentation .

If I had a PostgreSQL table foo that looks like

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]}

Why does this query give me these results?

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;

Specifically, why does @? support $.values[*].id (described on that page in another section ) but JSONB_SET uses some other path format {bar,3,baz} ?

Ultimately, what I would like to do and don't know how, is to remove non-alphanumeric characters (eg underscores in this example) in all id values represented by the path $.values[*].id .

The reason is that the operators have different data types on the right hand side.

SELECT oprname, oprright::regtype
FROM pg_operator
WHERE oprleft = 'jsonb'::regtype
  AND oprname IN ('@?', '#>');

 oprname | oprright 
---------+----------
 #>      | text[]
 @?      | jsonpath
(2 rows)

Similarly, the second argument of jsonb_set is a text[] .

Now '$.values[*].id' is a valid jsonpath , but not a valid text[] literal.

Thanks for the answers and comments about why the data types were different.

I wanted to post how I solved my problem:

Ultimately, what I would like to do and don't know how, is to remove non-alphanumeric characters (eg 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM