Search code examples
postgresqlforeachplpgsqljsonb

Getting null when requesting value from jsonb


I have loop for each element_id and nested loop for jsonb in array, and when I want to get value from jsonb by key I get null:

create procedure elements_to_entries_add(IN entry_ids uuid[], IN element_ids uuid[], IN element_values jsonb[])
    language plpgsql
as
$$
<<main_label>>
DECLARE
    singe_jsonb_with_values JSONB := '[]';
BEGIN    
    <<elements_n_values_relationship_create>>
    BEGIN
        <<elements_n_values_add_elements_without_values>>
        DECLARE
            element_id UUID;
            element_n_value_relationship JSONB;
            flag BOOLEAN := false;

        BEGIN
            FOREACH element_id IN ARRAY element_ids
            LOOP
                FOREACH element_n_value_relationship IN ARRAY element_values
                LOOP   
                    RAISE LOG 'INSIDE NESTED LOOP obj % , element_id %', element_n_value_relationship, element_n_value_relationship ->> 'element_id';
                    IF element_id::UUID = (element_n_value_relationship ->> 'element_id')::UUID THEN
                        flag := true;
                        EXIT;
                    END IF ;

                END LOOP;

                IF NOT flag THEN
                    singe_jsonb_with_values := singe_jsonb_with_values || jsonb_build_array(jsonb_build_object('element_id', element_id, 'value', NULL));
                ELSE  
                    singe_jsonb_with_values := singe_jsonb_with_values || jsonb_build_array(element_n_value_relationship);
                END IF;
            
                flag := false;

            END LOOP;
           
        END;

    END;
    
    INSERT INTO m2m_entries_n_elements(entry_id, element_id, value)
    SELECT entry_id, element_id, value
    FROM (
        UNNEST(entry_ids) as entry_id
        CROSS JOIN (
            SELECT
                element_id,
                CASE
                    WHEN value IS NULL THEN
                        CASE
                            WHEN element_type = 1 THEN
                                (attributes -> 'default_value')::JSONB
                            WHEN element_type = 7 THEN
                                (attributes -> 'default_location')::JSONB
                            WHEN element_type = 3 THEN
                                (attributes -> 'default_divider')::JSONB
                        END
                    ELSE value
                END
            FROM (
                jsonb_to_recordset(singe_jsonb_with_values::JSONB) as x(element_id UUID, value JSONB)
                INNER JOIN elements ON x.element_id = elements.id
            ) AS element_rows_part
        ) as t(element_id, value)
    ) AS new_rows(entry_id, element_id, value)
    WHERE NOT EXISTS(
        SELECT 1
        FROM m2m_entries_n_elements
        WHERE m2m_entries_n_elements.entry_id = new_rows.entry_id::UUID
        AND m2m_entries_n_elements.element_id = new_rows.element_id::UUID
    );
end;
$$;


Some raise logs:

INSIDE NESTED LOOP obj
"{\"element_id\":\"ceeb364e-bb88-4f41-9c56-9e5f4d0bc1fb\",\"value\":null}"
, element_id <NULL>

INSIDE NESTED LOOP obj
"{\"element_id\":\"e9a9ce50-a324-4529-87ef-8fdc35a3ce48\",\"value\":\"abc\"}"
, element_id <NULL>

INSIDE NESTED LOOP obj
"{\"element_id\":\"a7993f3d-9256-4354-a147-5b9d18d7812b\",\"value\":true}"
, element_id <NULL>

So when I try to compare element_id from an external loop with element_id from jsonb, I will always try to compare <uuid> == <null> and never execute flag:=true.

Why does element_n_value_relationship, element_n_value_relationship ->> 'element_id' always return null?

Postgres version: 14


Solution

  • Okay, I fixed it. This is going to seem really stupid, but maybe someone else will fall for it. The pl/pgsql procedure had nothing to do with it, it turned out that I didn't have a jsonb object itself coming in, but a jsonb that contained a single element - a string that contained the object itself.

    Excepted jsonb:

    {"element_id": <uuid>, "value": "some value"}
    

    Actual coming jsonb inside procedure:

    '{"element_id": <uuid>, "value": "some value"}'