1

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
    – Joven28
    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.
    – ravioli
    Sep 23, 2019 at 5:41
  • And jsonb wasn't added until 9.5 Sep 23, 2019 at 5:43
2

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

6
  • It works only for a single row, any idea how can I loop over all rows ?
    – Nil Null
    Sep 23, 2019 at 7:26
  • 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 ?
    – Nil Null
    Sep 23, 2019 at 8:03
  • 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?
    – ravioli
    Sep 23, 2019 at 8:30
  • It has an ID as primary key. I tried your approach but it is copying all rows
    – Nil Null
    Sep 23, 2019 at 9:33
  • what do you mean by "tgt" table ?
    – Nil Null
    Sep 23, 2019 at 10:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.