如何根据嵌套键值删除JSONB列中的数组元素?
How to delete array element in JSONB column based on nested key value?
如何根据对象键之一的值从数组中删除对象?
数组嵌套在父对象中。
这是一个示例结构:
{
"foo1": [ { "bar1": 123, "bar2": 456 }, { "bar1": 789, "bar2": 42 } ],
"foo2": [ "some other stuff" ]
}
我可以根据 bar1
的值删除数组元素吗?
我可以使用 columnname @> '{ "foo1": [ { "bar1": 123 } ]}'
基于 bar1
值进行查询,但我没有找到一种方法从 foo1
中删除 { "bar1": 123, "bar2": 456 }
同时保留其他一切都完好无损。
谢谢
运行 PostgreSQL 9.6
假设你要搜索一个特定的对象,里面有一个特定值的对象,并且这个特定的对象可以出现在数组的任何地方,你需要解压文档和每个数组,测试适当包含和删除内部子文档,然后重新 assemble 数组和 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)
这在您的 table 上使用横向连接来获取 JSON 文档 jdoc
并将其转换为一组行 foo(id, key, value)
其中 value
包含数组。 id
是您的 table.
的主键
然后我们得到:
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
。在 select 列表中,数组由 id
和 key
重新 assembled,但现在没有违规的子文档。
最后,在主查询中 JSON 文档被重新 assembled:
SELECT id, jsonb_build_object(key, jarray)
FROM x -- from above
GROUP BY 1;
要理解的重要一点是 PostgreSQL JSON 函数仅在您可以明确指示的 JSON 文档级别上运行。通常这是文档的顶层,除非你有一个明确的路径到文档中的某个级别(比如 {foo1, 0, bar1}
,但你没有那个)。在该级别的操作中,您可以解压缩以进行处理,例如删除对象。
如何根据对象键之一的值从数组中删除对象?
数组嵌套在父对象中。
这是一个示例结构:
{
"foo1": [ { "bar1": 123, "bar2": 456 }, { "bar1": 789, "bar2": 42 } ],
"foo2": [ "some other stuff" ]
}
我可以根据 bar1
的值删除数组元素吗?
我可以使用 columnname @> '{ "foo1": [ { "bar1": 123 } ]}'
基于 bar1
值进行查询,但我没有找到一种方法从 foo1
中删除 { "bar1": 123, "bar2": 456 }
同时保留其他一切都完好无损。
谢谢
运行 PostgreSQL 9.6
假设你要搜索一个特定的对象,里面有一个特定值的对象,并且这个特定的对象可以出现在数组的任何地方,你需要解压文档和每个数组,测试适当包含和删除内部子文档,然后重新 assemble 数组和 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)
这在您的 table 上使用横向连接来获取 JSON 文档 jdoc
并将其转换为一组行 foo(id, key, value)
其中 value
包含数组。 id
是您的 table.
然后我们得到:
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
。在 select 列表中,数组由 id
和 key
重新 assembled,但现在没有违规的子文档。
最后,在主查询中 JSON 文档被重新 assembled:
SELECT id, jsonb_build_object(key, jarray)
FROM x -- from above
GROUP BY 1;
要理解的重要一点是 PostgreSQL JSON 函数仅在您可以明确指示的 JSON 文档级别上运行。通常这是文档的顶层,除非你有一个明确的路径到文档中的某个级别(比如 {foo1, 0, bar1}
,但你没有那个)。在该级别的操作中,您可以解压缩以进行处理,例如删除对象。