Запросы к jsonb
На SQL можно написать порой ужасные вещи, например:
SELECT id, jsonb_path_query_array(value, '$[*].entityType')
FROM demo WHERE value @? '$[*] ? (@.entityId == 1 &&
(!exists (@.childrenIds) || exists (@.childrenIds ? (@[*] == 4))))';
Выглядит как совсем другой язык, потому что идет обращение к jsonb. Одно дело хранить неструктурированные данные в jsonb, но гонять по ним запросы — это уже звоночек. Для какой-нибудь отладки это еще куда ни шло, хотя там быстрее будет сделать большую часть операций вручную, чем написать полностью корректный запрос. Но в основном коде это делать — это признак того, что кто-то не смог нормально смоделировать бизнес сущности или использует данные по какому-то извращенному сценарию.
А в запросе выбираются элементы массива, в которых есть объект с entityId
и либо пустым childrenIds
, либо содержащим 4
. В ответе выдаются только значения полей entityType
.
Полный пример
CREATE TABLE demo(
id int not NULL,
value jsonb Not NULL
);
INSERT into demo VALUES
(1, '[{"entityId": 1, "entityType": "type1", "childrenIds": []}, {"entityId": 10, "entityType": "type5", "childrenIds": [30, 20]}]'::jsonb),
(2, '[{"entityId": 1, "entityType": "type2"}, {"entityId": 15, "entityType": "type1", "childrenIds": [4, 20]}]'::jsonb),
(3, '[{"entityId": 1, "entityType": "type3", "childrenIds": [5, 4]}, {"entityId": 25, "entityType": "type4", "childrenIds": [30, 4]}]'::jsonb),
(4, '[{"entityId": 35, "entityType": "type4", "childrenIds": [35, 4]}]'::jsonb);
SELECT id, jsonb_path_query_array(value, '$[*].entityType')
FROM demo WHERE VALUE @? '$[*] ? (@.entityId == 1 && (!exists (@.childrenIds) || exists (@.childrenIds ? (@[*] == 4))))';
Поиграться можно тут. В ответе будет 2 и 3 запись.