I have a column type text, with json object in it, in my table like :
{{"name":"MyName","age":10.0, "attribut":{"attack":"20","defence":30},{"name":"yourName","age":20.0}}
And i want to multiply all number *2 as :
{{"name":"MyName","age":20.0, "attribut":{"attack":"40","defence":60},{"name":"yourName","age":40.0}}
But i don't know how deep is the json object, and i don't know the keys, it's not regular.
How to multiply all number values of a json object ?
My failed tentative was to look around jsonb_* and replace functions:
tentative 1 : I tried to get all the path to the values as {key1,key2} in a column as sub-request and combin it with an other request but all my test failed avoid the error of when a key doesn't exist...
SQL Error [22023]: ERROR: cannot call jsonb_object_keys on a scalar
SELECT keys1.*, keys2.*, keys3.*, keys4.*
FROM schema.table,
jsonb_object_keys(schema.table.values_detail::jsonb) AS keys1 (key1),
jsonb_object_keys(schema.table.values_detail::jsonb -> keys1 ) AS keys2 (key2),
jsonb_object_keys(schema.table.values_detail::jsonb -> keys1 -> keys2 ) AS keys3 (key3)
WHERE id = '1afd3d7e-d05v-4d63-9cef-8fb9f6f9514f';
UPDATE
schema.table
SET
values_detail = (
SELECT
jsonb_object_agg(CASE
WHEN jsonb_typeof(values_detail::jsonb #> paths) = 'number'
THEN jsonb_set(values_detail::jsonb, ... ))
END)
FROM
sub-request as paths
)::text
WHERE id = '1afd3d7e-d05v-4d63-9cef-8fb9f6f9514f';
tentative 2 : Then i tried, get only numbers of the text, and multiply the numbers, and replace them back, but code not accept it, the regex match : \1 can't be convert as int.
SQL Error [22P02]: ERROR: invalid input syntax for integer: "\1"
SELECT
values_detail AS origin-json,
regexp_replace(
values_detail,
':([0-9]+)',
CONCAT(':',
CAST( (CAST('\1' AS int)*2) AS text)
)
, 'ig'
) AS transformed-json
FROM schema.table
WHERE id = '1afd3d7e-d05v-4d63-9cef-8fb9f6f9514f';
The approach below uses a
cteto iterate over the string from left to right, consuming integers when they occur as a value to a particular key and concatenating the result of their double to a running placeholder string, and appending non-integer characters to the placeholder if an integer is not found:See fiddle