Як отримати конкретний об'єкт з масиву jsonb в PostgreSQL?


16

У мене є поле під назвою "user", яке містить масив json, який приблизно так виглядає:

"user":

[{ "_id" : "1", "count" : "4" }, { "_id" : "3", "count": "4"}]

Тепер я хочу запит на зразок:

select count from tablename where id = "1"

Я не в змозі отримати конкретне поле countз масиву об’єктів json в PostgreSQL 9.4.

Відповіді:


17

Набагато ефективніше було б зберігати свої значення в нормалізованій схемі. Однак, ви також можете змусити це працювати з вашим поточним налаштуванням.

Припущення

Припускаючи це визначення таблиці:

CREATE TABLE tbl (tbl_id int, usr jsonb);

"user" - це зарезервоване слово, і воно потребує подвійного цитування, щоб використовуватись як назва стовпця. Не робіть цього. Я використовую usrзамість цього.

Запит

Запит не такий тривіальний, як здається (видалені) коментарі:

SELECT t.tbl_id, obj.val->>'count' AS count
FROM   tbl t
JOIN   LATERAL jsonb_array_elements(t.usr) obj(val) ON obj.val->>'_id' = '1'
WHERE  t.usr @> '[{"_id":"1"}]';

Є три основні етапи :

1. Визначте кваліфіковані рядки дешево

WHERE t.usr @> '[{"_id":"1"}]'ідентифікує рядки з відповідним об'єктом у масиві JSON. Вираз може використовувати загальний індекс GIN на jsonbстовпці або один із більш спеціалізованим класом операторів jsonb_path_ops:

CREATE INDEX tbl_usr_gin_idx ON tbl USING gin (usr jsonb_path_ops);

Додане WHEREзастереження логічно є зайвим , але для цього потрібно використовувати індекс. Вираз у пункті приєднання застосовує ту саму умову, але лише після вилучення масиву в кожному рядку, що кваліфікується до цього часу. За допомогою підтримки індексу Postgres обробляє лише рядки, які містять кваліфікований об'єкт, для початку. Не має великого значення для маленьких таблиць, робить велику різницю з великими таблицями та лише кількома кваліфікованими рядами.

Пов'язані:

2. Визначте відповідні об’єкти (масиви) у масиві

Нечесно з jsonb_array_elements(). ( unnest()добре лише для типів масивів Postgres.) Оскільки нас цікавлять лише фактично відповідні об’єкти, фільтруйте в умові приєднання відразу.

Пов'язані:

3. Значення вилучення для вкладеного ключа 'count'

Після кваліфікації об'єкти були вилучені, просто: obj.val->>'count'.


2
Звідки береться obj(value)? Це на LATERAL JOIN, jsonb_array_elementsчи десь ще?
Тайлер ДеВітт

Схоже, форматування, можливо, зіпсувалося. Я правильно читаю, JOIN LATERAL jsonb_array_elements(t.usr) obj(value) is short for JOIN LATERAL jsonb_array_elements(t.usr) AS obj(value)що obj(value)це псевдонім таблиці та стовпців? У цьому прикладі, якщо objце псевдонім таблиці, до чого це псевдонім? Набір повернувся з jsonb_array_elements?
Тайлер ДеВітт

1
так, і так. я видалив мій зашифрований коментар.
Ервін

Чи потрібно використовувати псевдонім стовпця? У моєму тестуванні JOIN LATERAL jsonb_array_elements(t.usr) obj ON obj->>'_id' = '1'мав такий самий ефект (після оновлення оператора select valueзамість val). Здається, jsonb_array_elements(t.usr)повертає таблицю з лише одним стовпцем. Чи розумні постиги і розуміють, що obj ->>це те саме obj.val ->>?
Тайлер ДеВітт

Маючи лише один стовпець, Postgres використовує даний псевдонім як назву таблиці та стовпців. Я просто явний, оскільки існує багато функцій повернення набору, які повертають більше одного стовпця.
Ервін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.