2016-11-04 52 views
2

我想将来自同级记录的一些数据聚合到单个jsonb字段中。在Postgres中更新带有计算数据结构的JSONB字段

下面是一个例子的数据结构,非常类似于一个我的工作:

CREATE TABLE so.a (
    id integer, 
    foo integer, 
    bar integer, 
    -- a lot of other data 
    CONSTRAINT a_pkey PRIMARY KEY (id) 
); 

CREATE TABLE so.b (
    id integer, 
    a1 integer, 
    a2 integer, 
    data jsonb, 
    CONSTRAINT b_pkey PRIMARY KEY (id), 
    CONSTRAINT "a1_fkey" FOREIGN KEY (a1) REFERENCES so.a (id), 
    CONSTRAINT "a2_fkey" FOREIGN KEY (a2) REFERENCES so.a (id) 
); 

和一些示例数据集中:

INSERT INTO so.a VALUES 
    (1, 42, 24), 
    (2, 22, 33), 
    (3, 66, 99); 

INSERT INTO so.b VALUES 
    (1, 1, 2, NULL), 
    (2, 2, 3, NULL), 
    (3, 3, 1, NULL); 

现在我要填写b.data一行来自同级记录的数据a1a2

data = [{ 
    "foo": a1.foo, 
    "bar": a1.bar 
}, { 
    "foo": a2.foo, 
    "bar": a2.bar 
}] 

我想出了最好的解决办法是建立使用to_json功能和字符串连接运算符||第一,然后才将其转换一个json字符串jsonb

UPDATE 
    so.b 
SET 
    data = ('[{ 
    "foo": ' || to_json(t1.foo) || ', 
    "bar": ' || to_json(t1.bar) || ' 
    }, { 
    "foo": ' || to_json(t2.foo) || ', 
    "bar": ' || to_json(t2.bar) || ' 
    }]')::jsonb 
FROM 
    so.a t1, 
    so.a t2 
WHERE 
    t1.id = b.a1 AND 
    t2.id = b.a2; 

这个解决方案工作得很好:

SELECT id, data FROM so.b; 
-- 1, [{"bar": 24, "foo": 42}, {"bar": 33, "foo": 22}] 
-- 2, [{"bar": 33, "foo": 22}, {"bar": 99, "foo": 66}] 
-- 3, [{"bar": 99, "foo": 66}, {"bar": 24, "foo": 42}] 

但对我来说似乎太笨拙了。

所以我想知道,也许有更好的方法来实现我想要的。


UPD:只是认为它可能会帮助,如果我还会介绍我以前试图解决这个问题。

我想保持的东西简单,所以我试图用array_to_json功能:

SET 
    data = array_to_json(ARRAY[t1, t2]) 

但是我已经结束了,在我的数据库了很多多余的数据。由于我找不到限制t1t2字段的方法,我放弃了这种方法。

回答

1

我认为你唯一能做的就是用jsonb_build_*函数代替字符串连接。 I.e:

UPDATE so.b SET 
    data = jsonb_build_array( 
     jsonb_build_object( 
      'foo', to_json(t1.foo), 
      'bar', to_json(t1.bar) 
     ), 
     jsonb_build_object( 
      'foo', to_json(t2.foo), 
      'bar', to_json(t2.bar) 
     ) 
    ) 
FROM 
    so.a t1, so.a t2 
WHERE 
    t1.id = b.a1 AND t2.id = b.a2;