为PostgreSQL JSONB列选择给定键内的条目数

时间:2016-05-13 16:09:18

标签: postgresql jsonb

我有一个带有示例内容的jsonb列,如下所示:

{"kay1": val1, "myMap": {"UniqueKey1": "UniqueValue1", "UniqueKey2": "UniqueValue2", "UniqueKey3": "UniqueValue3", "UniqueKey4": "UniqueValue4"}, "key2": {"key3": {"key4": "val4"}, "val3": {"key5": "val5"}}

我想找到'myMap'中的条目数大于/等于/小于某个整数的所有行 - 我有几百万这样的行,所以如果也可以使用索引,这将是有帮助的!

在上面的示例中,'myMap'中有4个条目。因此,对于查询类似“select * from myTable,其中jsonb_key_length(myJsonbColumn - >'myMap')= 4”,应返回上面的行。 [假设有一个函数jsonb_key_length()返回给定json对象的长度]

我在这里找到了类似的问题:Postgres json key count

但是,它需要键的名称,这可以在不使用键名的情况下完成吗?

解决方案

  

感谢@jmelesky提出的建议。

以下查询为我工作:

SELECT id, count(elements)
FROM (SELECT id, jsonb_object_keys(column -> 'myMap') AS elements
      FROM myTable GROUP BY id
     ) x
GROUP BY id
  

包括@ jmelesky的建议

SELECT id, (SELECT count(*)
            FROM (SELECT jsonb_object_keys(a->'myMap')
                  FROM test_json x where x.id = y.id
                  ) z
            ) count
FROM test_json y group by id;
  

找到另一个更快的解决方案

SELECT id, ARRAY_LENGTH(ARRAY(SELECT jsonb_object_keys(column -> 'myMap')), 1) AS count
FROM myTable

使用索引:
创建一个函数:

CREATE OR REPLACE FUNCTION jsonb_object_keys_length(_j jsonb)
RETURNS INT LANGUAGE SQL IMMUTABLE AS
'SELECT ARRAY_LENGTH(ARRAY(SELECT jsonb_object_keys(column -> 'myMap')), 1)';

创建索引:

CREATE INDEX idx_myMapCount ON myTable (jsonb_object_keys_length(column -> 'myMap'));

在查询中使用函数:

SELECT id, jsonb_object_keys_length(column -> 'myMap') AS count
FROM myTable

如果有更好的方法来建模此查询,请建议。谢谢!

1 个答案:

答案 0 :(得分:4)

function名为json_object_keys,这可能是此问题的关键部分。它接受一个json对象并将键作为关系的行返回。

=# create table test_json (a json);
CREATE TABLE
=# insert into test_json values ('{"kay1": 1, "myMap": {"UniqueKey1": "UniqueValue1", "UniqueKey2": "UniqueValue2", "UniqueKey3": "UniqueValue3", "UniqueKey4": "UniqueValue4"}, "key2": {"key3": {"key4": "val4"}, "val3": {"key5": "val5"}}}');
INSERT 0 1
=# select json_object_keys(a) from test_json;
 json_object_keys 
------------------
 kay1
 myMap
 key2
(3 rows)
=# select json_object_keys(a->'myMap') from test_json;
 json_object_keys 
------------------
 UniqueKey1
 UniqueKey2
 UniqueKey3
 UniqueKey4
(4 rows)

从那里,您可以将其包装在子查询中,如下所示:

=# select count(*) from (select json_object_keys(a->'myMap') from test_json) x;
 count 
-------
     4
(1 row)

编辑添加:有一个jsonb等效项(jsonb_object_keys),与jsonb值的工作方式相同。对不起,我倾向于用vanilla json做我的测试用例。