0

I have a table with a column called data that contains some JSON. If the data column for any given row in the table is not null, it will contain a JSON-encoded object with a key called companyDescription. The value associated with companyDescription is an arbitrary JavaScript object.

If I query my table like this

select data->>'companyDescription' from companies where data is not null;

I get rows like this

{"ops":[{"insert":"\n"}]}

I am trying to update all rows in the table so that the companyDescription values will be wrapped in another JSON-encoded JavaScript object in the following manner:

{"type":"quill","content":{"ops":[{"insert":"\n"}]}}

Here's what I have tried, but I think it won't work because the ->> operator is for selecting some JSON field as text, and indeed it fails with a syntax error.

update companies
set data->>'companyDescription' = CONCAT(
  '{"type":"quill","content":',
  (select data->>'companyDescription' from companies),
  '}'
);

What is the correct way to do this?

1 Answer 1

1

You can use a function jsonb_set. Currently XML or JSON values are immutable. You cannot to update some parts of these values. You can replace these values by some new modified value.

postgres=# select * from test;
┌──────────────────────────────────────────────────────────────────────┐
│                                  v                                   │
╞══════════════════════════════════════════════════════════════════════╡
│ {"companyId": 10, "companyDescription": {"ops": [{"insert": "\n"}]}} │
└──────────────────────────────────────────────────────────────────────┘
(1 row)

postgres=# select jsonb_build_object('type', 'quill', 'content', v->'companyDescription') from test;
┌───────────────────────────────────────────────────────────┐
│                    jsonb_build_object                     │
╞═══════════════════════════════════════════════════════════╡
│ {"type": "quill", "content": {"ops": [{"insert": "\n"}]}} │
└───────────────────────────────────────────────────────────┘
(1 row)

postgres=# select jsonb_set(v, ARRAY['companyDescription'], jsonb_build_object('type', 'quill', 'content', v->'companyDescription')) from test;
┌────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                             jsonb_set                                              │
╞════════════════════════════════════════════════════════════════════════════════════════════════════╡
│ {"companyId": 10, "companyDescription": {"type": "quill", "content": {"ops": [{"insert": "\n"}]}}} │
└────────────────────────────────────────────────────────────────────────────────────────────────────┘
(1 row)

So you final statement can looks like:

update companies
  set data = jsonb_set(data::jsonb, 
                       ARRAY['companyDescription'], 
                       jsonb_build_object('type', 'quill', 
                                          'content', data->'companyDescription'))
  where data is not null;
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you; that explains why all my previous search results showed examples in jsonb instead of json. How do I get the v in your example? I'm trying to use my original select, but I am not sure how map each row to itself. Do I need to use some kind of loop? Here's what I am trying: ix.io/2m5u
@JezenThomas - v is column name, it is data. I'll fix this query
Excellent, thanks. This does indeed work; just needs the explicit data::JSONB typecast.

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.