0

I have a table in postgres that contains column of type jsonb, i used to save in this field array of jsons in this format.

post_id                             |questions                                                                                                                                                                                      |
------------------------------------|---------------------------------------
70071d97-06a8-401f-abfc-20ddada4f402|[{"question": "TEST QUESTION", "transaction_id": "ac547b52-72f3-444e-800c-46aaa48855a5"}, {"question":   "TEST QUESTION", "transaction_id": "ac547b52-72f3-444e-800c-46aaa48855ab"}]|

i want to delete an item in that list based on the transaction_id.

post_id                             |questions                                                                                                                                                                                 |
------------------------------------|---------------------------------------
70071d97-06a8-401f-abfc-20ddada4f402|[{"question": "TEST QUESTION", "transaction_id": "ac547b52-72f3-444e-800c-46aaa48855a5"}]|

I have tried couple of methods but None worked, i tried

select questions - '{"question": "TEST QUESTION", "transaction_id": "ac547b52-72f3-444e-800c-46aaa48855a5"}' from posts where post_id = '70071d97-06a8-401f-abfc-20ddada4f402';
1
  • please show us what you tried so far Commented Jul 16, 2019 at 8:30

3 Answers 3

4

step-by-step demo:db<>fiddle

UPDATE posts p
SET questions = data
FROM (
    SELECT
        questions,
        jsonb_agg(elems.value) AS data                       -- 3
    FROM
        posts,
        jsonb_array_elements(questions) elems                -- 1
    WHERE                                                    -- 2
        not (elems.value ->> 'transaction_id' = 'ac547b52-72f3-444e-800c-46aaa48855a5')
    GROUP BY questions
) s
WHERE s.questions = p.questions;
  1. Expand array into one row per array element
  2. Filter out the element to be deleted
  3. Group all remaining element into a new array
Sign up to request clarification or add additional context in comments.

2 Comments

If it's important to preserve the original order in the array, you can use with ordinality: dbfiddle.uk/…
Thanks for your response it was really helpfull, i made a slightly modified version of your original code, juste in case of we delete all items in that array we cant add more items to it so i made sure that if its null i replace it with empty array.
0

Thanks for S-Man response . i was able to acheive what exactly i wanted.

update edz_posts set questions =     
(SELECT
    '[]'::jsonb || jsonb_agg(elems.value)
FROM
    edz_posts,
    jsonb_array_elements(questions) elems 
where post_id = :post_id and universe_id=:universe_id
and not (elems.value ->> 'transaction_id' = :transaction_id)
group by questions)
where post_id = :post_id and universe_id=:universe_id
;
update edz_posts set questions = '[]'::jsonb where questions is null ;

Comments

0

This is my upgrade of the S-Man/a_horse_with_no_name examples for updating room table with uid identifier & message jsonb column. This way if there are no messages left, empty [] is inserted instead.

Room

uid messages
a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 { 'message_uid': 'test_id', text: 'hello' }
do $$
declare
    filtered jsonb;
BEGIN

SELECT
    messages,
    jsonb_agg(elems.value order by elems.idx) AS data
FROM
    room,
    jsonb_array_elements(messages) with ordinality as elems(value, idx)
WHERE
    not (elems.value ->> 'text' = 'Hello2') and
    uid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'
GROUP BY messages
INTO filtered;

UPDATE room p
SET messages = COALESCE(filtered, '[]'::jsonb)
WHERE uid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11';
end $$

UPDATE: better version using a function

CREATE OR REPLACE FUNCTION filteredJsonB(messages jsonb, not_key TEXT, not_value TEXT)
   RETURNS jsonb 
  AS
$$
    DECLARE 
        filtered jsonb;
    BEGIN
        SELECT
            jsonb_agg(elems.value ORDER BY elems.idx) AS DATA
        FROM
            jsonb_array_elements(messages) WITH ordinality AS elems(VALUE, idx)
        WHERE
            NOT (elems.value ->> not_key = not_value)
        GROUP BY messages
        INTO filtered;
        RETURN filtered;
    END;
$$ LANGUAGE plpgsql;

do $$
BEGIN

  UPDATE room p
  SET messages = COALESCE(filteredJsonB(p.messages, 'text', 'Hello2'), '[]'::jsonb)
  WHERE uid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11';
END $$

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.