如何根据嵌套键值删除JSONB列中的数组元素?

时间:2016-11-15 03:41:42

标签: arrays postgresql jsonb

如何根据对象某个键的值从数组中删除对象?

数组嵌套在父对象中。

这是一个示例结构:

{
  "foo1": [ { "bar1": 123, "bar2": 456 }, { "bar1": 789, "bar2": 42 } ],
  "foo2": [ "some other stuff" ]
}

我可以根据bar1

的值删除数组元素

我可以使用bar1根据columnname @> '{ "foo1": [ { "bar1": 123 } ]}'值进行查询,但我还没有找到一种方法可以在保留时{ "bar1": 123, "bar2": 456 } foo1其他一切都完好无损。

由于

运行PostgreSQL 9.6

1 个答案:

答案 0 :(得分:3)

假设您要搜索具有特定值的内部对象的特定对象,并且该特定对象可以出现在数组中的任何位置,您需要解压缩文档和每个数组,测试内部子 - 根据需要进行包含和删除的文档,然后重新组装数组和JSON文档(未经测试):

SELECT id, jsonb_build_object(key, jarray)
FROM (
    SELECT foo.id, foo.key, jsonb_build_array(bar.value) AS jarray
    FROM (  SELECT id, key, value
            FROM my_table, jsonb_each(jdoc) ) foo,
        jsonb_array_elements(foo.value) AS bar (value)
    WHERE NOT bar.value @> '{"bar1": 123}'::jsonb
    GROUP BY 1, 2 ) x
GROUP BY 1;

现在,这可能看起来有点密集,所以选择分开:

SELECT id, key, value
FROM my_table, jsonb_each(jdoc)

这会使用表格上的横向连接来获取JSON文档jdoc并将其转换为foo(id, key, value)包含数组的行valueid是您表格的主键。

然后我们得到:

SELECT foo.id, foo.key, jsonb_build_array(bar.value) AS jarray
FROM foo,  -- abbreviated from above
     jsonb_array_elements(foo.value) AS bar (value)
WHERE NOT bar.value @> '{"bar1": 123}'::jsonb
GROUP BY 1, 2

这使用另一个横向连接将数组解压缩到bar(value)行。现在可以使用包含运算符搜索这些对象,以从结果集中删除对象:WHERE NOT bar.value @> '{"bar1": 123}'::jsonb。在选择列表中,数组由idkey重新汇编,但现在没有违规的子文档。

最后,在主查询中重新组装JSON文档:

SELECT id, jsonb_build_object(key, jarray)
FROM x  -- from above
GROUP BY 1;

要理解的重要一点是,PostgreSQL JSON函数只能在您可以明确指出的JSON文档级别上运行。通常这是文档的顶级,除非您在文档中有某个级别的显式路径(如{foo1, 0, bar1},但您没有)。在该操作级别,您可以解压缩以进行处理,例如删除对象。