4

I have a table with the following schema (postgresql 14):

message   sentiment     classification
any text  positive    mobile, communication

message are only string, phrases. sentiment is a string, only one word classification are string but can have 1 to many word comma separated

I would like to create a json field with these columns, like this:

{"msg":"any text", "sentiment":"positive","classification":["mobile,"communication"]}

Also, if possible, is there a way to consider the classification this way:

{"msg":"any text", "sentiment":"positive","classification 1":"mobile","classification 2" communication"}
2

3 Answers 3

2

The first part of question is easy - Postgres provides functions for splitting string and converting to json:

with t(message,   sentiment,     classification) as (values
('any text','positive','mobile, communication')
)
select row_to_json(x.*)
from (
  select t.message
       , t.sentiment
       , array_to_json(string_to_array(t.classification, ', ')) as classification
  from t
) x

The second part is harder - your want json to have variable number of attributes, mixed of grouped and nongrouped data. I suggest to unwind all attributes and then assemble them back (note the numbered CTE is actually not needed if your real table has id - I just needed some column to group by):

with t(message,   sentiment,     classification) as (values
('any text','positive','mobile, communication')
)
, numbered (id, message,   sentiment,     classification) as (
  select row_number() over (order by null)
       , t.*
  from t
)
, extracted (id,message,sentiment,classification,index) as (
  select n.id
       , n.message
       , n.sentiment
       , l.c
       , l.i
  from numbered n
  join lateral unnest(string_to_array(n.classification, ', ')) with ordinality l(c,i) on true
), unioned (id, attribute, value) as (
  select id, concat('classification ', index::text), classification
  from extracted
  union all
  select id, 'message', message
  from numbered
  union all
  select id, 'sentiment', sentiment
  from numbered
)
select json_object_agg(attribute, value)
from unioned
group by id;

DB fiddle

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

Comments

2

Use jsonb_build_object and concatenate the columns you want

SELECT 
  jsonb_build_object(
      'msg',message,
      'sentiment',sentiment,
      'classification',       
          string_to_array(classification,',')) 

FROM mytable;

Demo: db<>fiddle

The second output is definitely not trivial. The SQL code would be much larger and harder to maintain - not to mention that parsing such file also requires a little more effort.

Comments

1

You can use a cte to handle the flattening of the classification attributes and then perform the necessary grouping in the main queries for each problem component:

with cte(r, m, s, k) as (
   select row_number() over (order by t.message), t.message, t.sentiment, v.* from tbl t 
   cross join json_array_elements(array_to_json(string_to_array(t.classification, ', '))) v
)
-- first part --
select json_build_object('msg', t1.message, 'sentiment', t1.sentiment, 'classification', string_to_array(t1.classification, ', ')) from tbl t1
-- second part --
select jsonb_build_object('msg', t1.m, 'sentiment', t1.s)||('{'||t1.g||'}')::jsonb 
from (select c.m, c.s, array_to_string(array_agg('"classification '||c.r||'":'||c.k), ', ') g 
      from cte c group by c.m, c.s) t1

Comments

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.