在对象内部追加/推送或更新Jsonb数组

时间:2019-11-24 17:20:51

标签: arrays postgresql object jsonb

所以我在postgresql(版本12)中获得了以下架构

-- items table
CREATE TABLE items
(
    id          CHAR(27) PRIMARY KEY     NOT NULL DEFAULT new_ksuid(),
    name        TEXT                     NOT NULL,
    item_code VARCHAR(120)             NOT NULL UNIQUE,
    qty_loc     JSONB                    NOT NULL DEFAULT '{
      "whQty": []
    }',
    categories  TEXT[],
    upper       INTEGER                  NOT NULL DEFAULT 999,
    under       INTEGER                  NOT NULL DEFAULT 0,
    price_max   DECIMAL(20, 2),
    price_min   DECIMAL(20, 2),
    price_avg   DECIMAL(20, 2),
    created_at  TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at  TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    existed     BOOLEAN                  NOT NULL DEFAULT false
);
CREATE INDEX idx_name_items ON items USING gin (name gin_trgm_ops);
CREATE INDEX idx_item_code_items ON items USING gin (item_code gin_trgm_ops);

和以下功能

CREATE
    OR REPLACE FUNCTION upd_item_amount(wh_id CHAR(27),
                                        item_id CHAR(27),
                                        qty NUMERIC) RETURNS VOID
    LANGUAGE plpgsql AS
'
    DECLARE
        entry items%ROWTYPE;
    BEGIN
        SELECT EXISTS(
                       (SELECT id
                        INTO entry
                        FROM items, jsonb_array_elements(items.qty_loc -> ''whQty'')
                        WHERE value ? ''whId''
                          AND value ->> ''whId'' = wh_id
                          AND items.id = item_id)
                   );
        IF FOUND THEN
            WITH whq_idx AS (
                WITH whq AS (
                    WITH QTY_LOC_AGG AS (
                        SELECT jsonb_agg(value) AS loc
                        FROM items,
                            jsonb_array_elements(qty_loc -> ''whQty'')
                    )
                    SELECT items.id, loc
                    FROM items,
                         QTY_LOC_AGG
                )
                SELECT (''{'' || index - 1 || '',qty}'')::text[] as path
                FROM whq,
                     jsonb_array_elements(whq.loc) WITH ORDINALITY arr(wh_quantity, index)
                WHERE (wh_quantity ->> ''whId'') = wh_id
                  AND whq.id = item_id
            )
            UPDATE items
            SET qty_loc = jsonb_build_object(''whQty'',
                                             jsonb_set(qty_loc -> ''whQty'', whq_idx.path, qty, false)
                )
            FROM whq_idx
            WHERE items.id = item_id;
        ELSE
            UPDATE items
            SET qty_loc = jsonb_build_object(''whQty'',
                                             jsonb_set(qty_loc -> ''whQty'',
                                                       qty_loc -> ''whQty'' || ''{"whId": wh_id, "qty": qty}''
                                                 )
                )
            WHERE items.id = item_id;

        END IF;
    END';

在交互式psql中,我可以使用以下sql语句从第一个IF语句中执行UPDATE项目:

 WITH whq_idx AS (
                WITH whq AS (
                    WITH QTY_LOC_AGG AS (
                        SELECT jsonb_agg(value) AS loc
                        FROM items,
                            jsonb_array_elements(qty_loc -> ''whQty'')
                    )
                    SELECT items.id, loc
                    FROM items,
                         QTY_LOC_AGG
                )
                SELECT (''{'' || index - 1 || '',qty}'')::text[] as path
                FROM whq,
                     jsonb_array_elements(whq.loc) WITH ORDINALITY arr(wh_quantity, index)
                WHERE (wh_quantity ->> ''whId'') = wh_id
                  AND whq.id = item_id
            )
            UPDATE items
-- The error points to the following statement
            SET qty_loc = jsonb_build_object(''whQty'',
                                             jsonb_set(qty_loc -> ''whQty'', whq_idx.path, qty, false)
                )
-- ^^^
            FROM whq_idx
            WHERE items.id = item_id;

但是当我通过“ SELECT upd_item_amount('warehouseID','itemID',amount_of_item)'调用它(函数)时,出现以下错误:

ERROR: function jsonb_set(jsonb, text[], numeric, boolean) does not exist

HINT: No function matches the given name and argument types. You might need to add explicit type casts.

错误指向我的代码中的粗体部分。

有人可以指出我正确的方向吗?感谢任何帮助。非常感谢。

1 个答案:

答案 0 :(得分:0)

  

错误:函数jsonb_set(jsonb,text [],numeric,boolean)没有   存在

     

提示:没有函数与给定的名称和参数类型匹配。你可能   需要添加显式类型转换

您传递jsonb_set“ qty”作为第三个参数,它是数字类型。但是jsonb_set将JSONB作为其第三个参数。 PostgreSQL拒绝将数字隐式转换为jsonb。您可以将其指定为"qty"::text::jsonb来强制进行转换。