Расширение массива объектов, хранящихся в JSONB - PullRequest
2 голосов
/ 05 октября 2019

У меня есть таблица, включающая поле 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)
);

Вот несколько примеров данных из поля JSONB table_stats:

[
    {"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)

Может кто-нибудь заметить ошибку в моей настройке? Кажется, у меня есть нужные части, но я не могу их правильно собрать.

Postgres 11.4, развернутый на RDS.

Follow Up

GMB ответил на мой вопрос, но я хочу добавить сюда немного больше для архивов. В прошлом, когда я печатал ошибку (JSON вместо JSONB), суть всего этого заключается в том, что Postgres нужен шаблон / карта, которая определяет структуру элементов в массиве JSON / JSONB. Я думаю, что в этом случае есть четыре (?) Места, откуда могут поступать данные для набора:

  • Существующее определение таблицы, поскольку каждая таблица является типом.
  • Существующее представлениеопределение, так как каждое представление является типом. (Вы можете найти их в pg_class вместе с базовыми производными от таблицы типами.
  • Пользовательский тип, созданный с помощью CREATE TYPE, как я использовал выше.
  • In-Объявление строки.

Для сравнения, вот обновленный запрос, который использует пользовательский тип dfits, показанный выше:

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

А теперь вот еще одна версия, которая использует in-lineобъявление:

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 Ответ

2 голосов
/ 05 октября 2019

Поскольку вы используете столбец jsonb, вам действительно нужно jsonb_populate_recordset. Кроме того, эта функция возвращает набор записей, поэтому ее необходимо поместить в предложение FROM, а не в предложение SELECT.

Обратите внимание:

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

Демонстрация на 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          |
...