简体   繁体   English

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

[英]How to delete array element in JSONB column based on nested key value?

How can I remove an object from an array, based on the value of one of the object's keys? 如何根据对象的某个键的值从数组中删除对象?

The array is nested within a parent object. 该数组嵌套在父对象中。

Here's a sample structure: 这是一个示例结构:

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

Can I remove an array element based on the value of bar1 ? 我可以根据bar1的值删除数组元素吗?

I can query based on the bar1 value using: columnname @> '{ "foo1": [ { "bar1": 123 } ]}' , but I've had no luck finding a way to remove { "bar1": 123, "bar2": 456 } from foo1 while keeping everything else intact. 我可以使用以下命令查询bar1值: columnname @> '{ "foo1": [ { "bar1": 123 } ]}' ,但我没有找到删除{ "bar1": 123, "bar2": 456 }来自foo1 { "bar1": 123, "bar2": 456 }同时保持其他所有内容完好无损。

Thanks 谢谢


Running PostgreSQL 9.6 运行PostgreSQL 9.6

Assuming that you want to search for a specific object with an inner object of a certain value, and that this specific object can appear anywhere in the array, you need to unpack the document and each of the arrays, test the inner sub-documents for containment and delete as appropriate, then re-assemble the array and the JSON document (untested): 假设您要搜索具有特定值的内部对象的特定对象,并且该特定对象可以出现在数组中的任何位置,您需要解压缩文档和每个数组,测试内部子文档根据需要包含和删除,然后重新组装数组和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;

Now, this may seem a little dense, so picked apart you get: 现在,这可能看起来有点密集,所以选择分开你得到:

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

This uses a lateral join on your table to take the JSON document jdoc and turn it into a set of rows foo(id, key, value) where the value contains the array. 这使用表上的横向连接来获取JSON文档jdoc并将其转换为一组行foo(id, key, value) ,其中value包含数组。 The id is the primary key of your table. id是表的主键。

Then we get: 然后我们得到:

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

This uses another lateral join to unpack the arrays into bar(value) rows. 这使用另一个横向连接将数组解压缩到bar(value)行。 These objects can now be searched with the containment operator to remove the objects from the result set: WHERE NOT bar.value @> '{"bar1": 123}'::jsonb . 现在可以使用包含运算符搜索这些对象,以从结果集中删除对象: WHERE NOT bar.value @> '{"bar1": 123}'::jsonb In the select list the arrays are re-assembled by id and key but now without the offending sub-documents. 在选择列表中,数组由idkey重新组装,但现在没有违规的子文档。

Finally, in the main query the JSON documents are re-assembled: 最后,在主查询中重新组装JSON文档:

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

The important thing to understand is that PostgreSQL JSON functions only operate on the level of the JSON document that you can explicitly indicate. 需要了解的重要一点是,PostgreSQL JSON函数只能在您可以明确指出的JSON文档级别上运行。 Usually that is the top level of the document, unless you have an explicit path to some level in the document (like {foo1, 0, bar1} , but you don't have that). 通常这是文档的顶级,除非你有一个明确的路径指向文档中的某个级别(如{foo1, 0, bar1} ,但你没有)。 At that level of operation you can then unpack to do your processing such as removing objects. 在该操作级别,您可以解压缩以执行处理,例如删除对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM