按嵌套JSONB文档

时间:2017-05-26 19:57:55

标签: postgresql jsonb

我在PostgreSQL数据库(v 9.6)中有一个相当简单的表:

CREATE TABLE foobar (id serial, data jsonb);

以下是存储在数据列中的JSONB文档示例:

[{ key: 'foo', value: 100 }, { key: 'bar', value: 5 }, { key: 'baz', value: 10 }]

我正在尝试编写一个select,它将返回满足JSONB文档中条件的每一行,并仅选择指定的嵌套文档;即,foo大于X的每一行都返回以baz为键的所有嵌套文档。

到目前为止,我已经提供了这样的查询,但它不起作用 - 它返回0条记录。

SELECT id
  FROM foobar
 WHERE (data->>'key' = 'foo' AND (data->>'value')::numeric > 5)
    OR (data->>'key' = 'bar' AND (data->>'value')::numeric < 10)

如果有人知道如何优化最终查询,那也很棒。谢谢!

2 个答案:

答案 0 :(得分:3)

  对于foo大于X的每一行,

返回所有以baz为键的嵌套文档。

两次使用foo。第一个用于将值与键baz进行比较,第二个用于查找带有键with foobar(id, data) as ( values (1, '[ { "key": "foo", "value": 100 }, { "key": "bar", "value": 5 }, { "key": "baz", "value": 10 } ]'::jsonb) ) select id, value_baz from foobar, jsonb_array_elements(data) el_foo(value_foo), jsonb_array_elements(data) el_baz(value_baz) where value_foo->>'key' = 'foo' and (value_foo->>'value')::numeric > 5 and value_baz->>'key' = 'baz'; id | value_baz ----+----------------------------- 1 | {"key": "baz", "value": 10} (1 row) 的对象:

'{ "foo": 100, "bar": 5, "baz": 10 }'

你的json专栏的格式很奇怪。我认为没有理由在这里使用json数组。您可以使用以下简单形式存储相同的信息:

with foobar(id, data) as (
values
(1, '{ "foo": 100, "bar": 5, "baz": 10 }'::jsonb)
)

select id, data->'baz' as baz
from foobar
where (data->>'foo')::numeric > 5;

 id | baz 
----+-----
  1 | 10
(1 row) 

在这种情况下,您的查询可能非常简单:

ctx.instance.items = undefined;

答案 1 :(得分:0)

您可以通过以下方式实现此目的:

SELECT     id, jsonb_agg(e) FILTER (WHERE e ->> 'key' = 'bar')
FROM       foobar
CROSS JOIN jsonb_array_elements(data) e
WHERE      data @> '[{"key":"foo"},{"key":"bar"}]'
GROUP BY   id
HAVING     bool_or(e ->> 'key' = 'foo' AND e -> 'value' > '5')

备注

  • e -> 'value' > '5'会将value JSON属性与JSON值5进行比较,如果您在JSON文档中使用数字,它将完美运行。如果情况并非如此(即您还有JSON字符串,您希望将其作为数字处理),请使用CAST,例如(e ->> 'value')::numeric > 5
  • WHERE data @> '[{"key":"foo"},{"key":"bar"}]'完全是可选的。我包含在此处,因为您可以从GIN index(在jsonb列上;如果您有的话)中挤出最多的内容。但是,如果这些键几乎位于表中的每一行,那将几乎无用。
  • 不幸的是,每个解决方案都需要使用jsonb_array_elements(),这会破坏JSON索引的用例。使用您当前的设计,顺序表扫描是不可避免的(除非上面的谓词实际上可以过滤掉很多行)。

http://rextester.com/XCPB80482