Как запросить столбец JSON для пустых объектов?

Нужно найти все строки, где определенный столбец json содержит пустой объект, {}, Это возможно с массивами JSON или если я ищу определенный ключ в объекте. Но я просто хочу знать, пуст ли объект. Не могу найти оператора, который сделает это.

 dev=# \d test
     Table "public.test"
  Column | Type | Modifiers
 --------+------+-----------
  foo    | json |

 dev=# select * from test;
    foo
 ---------
  {"a":1}
  {"b":1}
  {}
 (3 rows)

 dev=# select * from test where foo != '{}';
 ERROR:  operator does not exist: json <> unknown
 LINE 1: select * from test where foo != '{}';
                                      ^
 HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
 dev=# select * from test where foo != to_json('{}'::text);
 ERROR:  operator does not exist: json <> json
 LINE 1: select * from test where foo != to_json('{}'::text);
                                      ^
 HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
 dwv=# select * from test where foo != '{}'::json;
 ERROR:  operator does not exist: json <> json
 LINE 1: select * from test where foo != '{}'::json;
                                      ^
 HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.

9 ответов

Решение

Для типа данных нет оператора равенства (или неравенства) json в целом, потому что равенство трудно установить. Ты будешь любить jsonb в Postgres 9.4, где это возможно. Подробнее в этом ответе на dba.SE (последняя глава):

Приведение обеих сторон выражения к text позволяет = или же <> операторы, но это не всегда надежно, есть много возможных текстовых представлений для того же json значение.

Для этого конкретного случая, однако, это работает просто отлично:

select * from test where foo::text <> '{}'::text;

Пустой массив JSON [] также может быть актуальным.

Тогда это может работать как для [] а также {}:

select * from test where length(foo::text) > 2 ;

Ты должен быть осторожен. Приведение всех ваших данных к другому типу для сравнения приведет к проблемам с производительностью в большой базе данных.

Если у ваших данных есть согласованный ключ, вы можете проверить его наличие. Например, если данные плана: {} или {id: '1'}

тогда вы можете искать предметы без идентификатора

SELECT * FROM public."user"
where NOT(plan ? 'id')

Начиная с PostgreSQL 9.5 этот тип запроса с данными JSON невозможен. С другой стороны, я согласен, что это было бы очень полезно, и создал запрос на это:

https://postgresql.uservoice.com/forums/21853-general/suggestions/12305481-check-if-json-is-empty

Не стесняйтесь голосовать, и, надеюсь, он будет реализован!

В 9.3 есть возможность подсчитать пары в каждом объекте и отфильтровать пары без

create table test (foo json);
insert into test (foo) values
('{"a":1, "c":2}'), ('{"b":1}'), ('{}');

select *
from test
where (select count(*) from json_each(foo) s) = 0;
 foo 
-----
 {}

или проверить существование, вероятно, быстрее для больших объектов

select *
from test
where not exists (select 1 from json_each(foo) s);

Оба метода будут работать безупречно, независимо от форматирования

Согласно документации по функциям и операторам JSON, вы можете использовать функцию двойной стрелки ( ->>), чтобы получить объект json или поле массива в виде текста. Затем выполните проверку равенства для строки.

Так что это сработало для меня:

      SELECT jsonb_col from my_table
WHERE jsonb_col ->> 'key' = '{}';

Или, если он вложен более чем в один уровень, используйте функцию пути ( #>>)

      SELECT jsonb_col from my_table
WHERE jsonb_col #>> '{key, nestedKey}' = '{}';

В настоящее время поддерживаемая версия на момент написания:

Поддерживаемые версии: текущая (13) / 12/11/10 / 9,6

Вы можете использовать Postgres<@(включен в) оператор, см. документацию:

      select '{"a":2, "b":"hello"}'::jsonb <@ '{}'::jsonb;  -- false
select '{}'::jsonb <@ '{}'::jsonb;                    -- true

select '[{"a":1}, {"a":2}, {"a":3}]'::jsonb <@ '[]'::jsonb;  -- false
select '[]'::jsonb <@ '[]'::jsonb;                           -- true

Функции JSON в функциях PostgreSQL 12jsonb_path_exists.

Чтобы избежать сериализации больших объектов jsonb, это правильно возвращает true, если объект не пуст:

      select data from block where jsonb_path_exists(data, '$ ? (exists (@.*))');
      SELECT * FROM Table_Name WHERE JSON_LENGTH(column_name) = 0
Другие вопросы по тегам