扩展存储在JSONB中的对象数组

时间:2019-10-04 22:22:14

标签: postgresql parsing jsonb

我有一个表,其中包含一个JSONB字段和一个JSON数组,并具有我想扩展的简单格式。这是表格定义的简化版本:

CREATE TABLE IF NOT EXISTS data.data_file_info (
    id uuid NOT NULL,
    server_name_ citext NOT NULL,
    table_stats jsonb DEFAULT '{}'::jsonb NOT NULL,
    PRIMARY KEY(id)
);

以下是来自table_stats JSONB字段的一些示例数据:

[
    {"table_name":"AutoReportOrg","record_count":48,"table_number":167},
    {"table_name":"AutoReportOrgAudit","record_count":0,"table_number":170},
    {"table_name":"AutoReportOrgRecipient","record_count":126,"table_number":168},
    {"table_name":"AutoReportRecipient","record_count":28,"table_number":169}
]

json_populate_recordset和/或json_to_recordset函数似乎应该是我所追求的,但是我无法使其正常工作。我查看了很多过去的问题,并尝试了各种语法。以下是我得到的印象应该起作用的信息……但事实并非如此:

-- Define a custom type to act as a template for the JSON parser.
DROP TYPE IF EXISTS dfits;
CREATE TYPE api.dfits AS (
    table_name citext,
    record_count int8,
    table_number int4);

-- And now we parse!
SELECT server_name_, (json_populate_recordset(null::dfits, table_stats)).* FROM data_file_info;

但是我回来了:

ERROR:  function json_populate_recordset(dfits, jsonb) does not exist
LINE 4: SELECT server_name_, (json_populate_recordset(null::dfits, t...
                              ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts. (Line 9)

有人可以发现我的设置中的错误吗?看来我有合适的作品,但我没有设法将它们正确地组合在一起。

已部署在RDS上的Postgres 11.4。

跟进

GMB回答了我的问题,但是我想在这里为档案添加更多内容。经过我的输入错误(JSON而不是JSONB)之后,这些问题的症结似乎在于Postgres需要一个模板/映射来定义JSON / JSONB数组中元素的结构。我认为在这种情况下,可以在四个(?)地方输入数据:

  • 现有的表定义,因为每个表都是一种类型。
  • 现有视图定义,因为每个视图都是一种类型。 (您可以在pg_class中找到它们以及基表派生的类型。
  • 使用CREATE TYPE创建的自定义类型,就像我上面使用的那样。
  • 嵌入式声明。

为进行比较,下面是一个更新的查询,该查询使用上面显示的自定义类型dfits

SELECT server_name_, expanded_json.*
FROM
   data_file_info, 
   jsonb_populate_recordset(null::dfits, table_stats) as expanded_json

现在这是另一个使用嵌入式声明的版本:

SELECT server_name_, expanded_json.*
FROM
   data_file_info, 
    jsonb_to_recordset(table_stats) as expanded_json 
        (table_name text, record_count int, table_number int)

我可以看到这两种方法的用处。但是,话虽这么说,CREATE TYPE确实很棒。而且,您可以将其与CREATE CAST结合使用,以生成非常紧凑且易于使用的代码。

1 个答案:

答案 0 :(得分:2)

由于您使用的是jsonb列,因此您实际上需要jsonb_populate_recordset。另外,此函数返回一组记录,因此需要将其放在FROM子句中,而不是SELECT子句中。

考虑:

SELECT server_name, x.*
FROM
   data_file_info, 
   jsonb_populate_recordset(null::dfits, table_stats) x

Demo on DB Fiddle

| server_name | table_name             | record_count | table_number |
| ----------- | ---------------------- | ------------ | ------------ |
| foo         | AutoReportOrg          | 48           | 167          |
| foo         | AutoReportOrgAudit     | 0            | 170          |
| foo         | AutoReportOrgRecipient | 126          | 168          |
| foo         | AutoReportRecipient    | 28           | 169          |
相关问题