2

i have a jsonb column like

{
    "foo":{"bar" :["b","c","d"]}
}

Which I want to convert all items of "bar" array to a json with a "name" key result shall be:

{
    "foo":{"bar" :[{"name":"b"},{"name":"c"},{"name":"d"}]}
}

I wish to do it using postgresql queries in all rows of my table.

I tried various queries and functions but my main issue is at wrapping part of my strings.

Tips and helps are appriciated

3
  • ["name":"b","name":"c","name":"d"] is invalid because it is not an object notation. Also same keys in the object is not allowed Commented Sep 23, 2019 at 3:59
  • 3
    Are you actually using Postgres 9.1? It looks like native JSON support wasn't added until 9.2 and JSONB wasn't added until 9.4. Commented Sep 23, 2019 at 5:41
  • And jsonb wasn't added until 9.5 Commented Sep 23, 2019 at 5:43

1 Answer 1

3

Assuming you're using a version of Postgres with JSON support (9.4+), this should get you close:

WITH cte(myJSON) AS (
  SELECT CAST('{"foo":{"bar" :["b","c","d"]}}'AS JSONB) AS MyJSON 

  UNION ALL

  SELECT CAST('{"foo":{"bar" :["e","f","g"]}}'AS JSONB) AS MyJSON  
) 

SELECT
  JSON_AGG(
    (SELECT ROW_TO_JSON(_) FROM (SELECT name) AS _)
  ) myrow
FROM (
  SELECT JSONB_ARRAY_ELEMENTS(myjson->'foo'->'bar') AS name,
    ROW_NUMBER() OVER() AS RowNum
  FROM cte
) src
GROUP BY src.RowNum

This will return [{"name":"b"},{"name":"c"},{"name":"d"}].

You can then construct your final JSON as needed.

SQL Fiddle
Reference

Update
This is very hacky and I'm sure there's a cleaner way, but I updated the query above to handle multiple rows. Just replace the CTE references with your actual table name and myjson with the name of your JSON column.

Output:

[{"name":"b"},{"name":"c"},{"name":"d"}]
[{"name":"e"},{"name":"f"},{"name":"g"}]

Let me know if that works.

Updated Update
Here's an UPDATE statement you can use:

UPDATE t1 tgt
SET jsoncol = JSONB_SET(
  jsoncol, -- Source JSON
  '{foo,bar}', -- Target node to update
  src.new_json -- New value 
)
FROM (
  SELECT 
    ID, 
    JSONB_AGG(
      (SELECT TO_JSONB(_) FROM (SELECT name) AS _) -- Convert new row to JSON
    ) new_json
  FROM (
    SELECT 
      ID, 
      JSONB_ARRAY_ELEMENTS(jsoncol->'foo'->'bar') AS name -- Convert array to rows
    FROM t1
  ) src
  GROUP BY src.ID
) src
WHERE tgt.ID = src.ID -- Update "tgt" table with rows from "src" table
;

DB-Fiddle

Sign up to request clarification or add additional context in comments.

6 Comments

It works only for a single row, any idea how can I loop over all rows ?
It works charm, but now I face another issue, I am updating this table which only bar supposed to change , any clue on how to write the update ?
You can use something like this: UPDATE MyTable SET jsoncol = JSONB_SET(jsoncol, '{foo,bar}', <new_JSON_value>). This will replace the value in foo->bar with new_JSON_value. If you want to use the query above you'll need to do an UPDATE FROM and join the "src" table to the "tgt" table. What is the PK of the table you want to update?
It has an ID as primary key. I tried your approach but it is copying all rows
what do you mean by "tgt" table ?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.