postgresql jsonb содержит ключ: значение на втором уровне

Есть ли возможность в postgresql запросить ключ: значение на втором уровне

например, поле строки jsonb выглядит так:

{
   "something": {
      "v_id": "5544d28431f19", 
      "value": "xyz"
   }, 
   "something_else": {
      "v_id": "5544d28431feb", 
      "value": "abc"
   }
}

Я хочу запросить эту строку, используя значение v_id, например:

  SELECT id, jsonb_field
  FROM table_1
  WHERE jsonb_field @> '{{"v_id": "5544d28431feb"}}'
  ;

Однако этот запрос недействителен. Как добиться такого запроса?

Изменить:

Согласно комментарию @ CraigRinger:

Дело здесь в том, что я не знаю ключа верхнего уровня, я хочу сказать: «для любого объекта существует внутренний объект, имеющий следующий ключ со следующим значением».


person Robin    schedule 02.05.2015    source источник
comment
Итак, дело здесь в том, что вы не знаете ключ верхнего уровня, который вы хотите сказать для любого объекта, существует ли внутренний объект со следующим ключом со следующим значением?   -  person Craig Ringer    schedule 02.05.2015
comment
@CraigRinger В том-то и дело   -  person Robin    schedule 02.05.2015
comment
Спасибо, хотел уточнить. Я не думаю, что здесь можно будет использовать индекс jsonb; это, вероятно, будет материал только для seqscan, если вы не создадите индекс выражения только для этого запроса.   -  person Craig Ringer    schedule 04.05.2015
comment
@CraigRinger Спасибо за ваш комментарий. Я действительно не рассматривал возможность указать v_id в качестве индекса jsonb. Вы бы порекомендовали мне это сделать, и почему здесь это невозможно?   -  person Robin    schedule 04.05.2015


Ответы (1)


Вы можете использовать lateral join для вызова jsonb_each для каждой строки в вашей таблице. Функция jsonb_each превращает каждый узел в строку с двумя столбцами, называемыми key и value:

select  value
from    table_1
cross join lateral
        jsonb_each(jsonb_field) sub
where   value @> '{"v_id": "5544d28431feb"}';

Полный пример (пока нет поддержки SQL Fiddle для Postgres 9.4):

create table table_1 (id int primary key, jsonb_field jsonb);
insert into table_1 (id, jsonb_field) values (42, '{
   "something": {
      "v_id": "5544d28431f19", 
      "value": "xyz"          
   },                                       
   "something_else": {
      "v_id": "5544d28431feb", 
      "value": "abc"
   }
}');

select  value
from    table_1
cross join lateral
        jsonb_each(jsonb_field) t2
where   value @> '{"v_id": "5544d28431feb"}';

Это печатает:

                   value                   
-------------------------------------------
 {"v_id": "5544d28431feb", "value": "abc"}
person Andomar    schedule 02.05.2015
comment
Привет, Андомар, твой пример отлично работает. Большое спасибо. Однако у меня небольшой вопрос: почему вы используете lateral_join? Мне удалось получить те же результаты с: FROM table_1 t1, jsonb_each(json_field) t2. Я не мог увидеть другую производительность с моими небольшими тестовыми данными. Есть ли здесь разница? - person Robin; 03.05.2015
comment
Похоже, что lateral подразумевается, если вы используете функцию в объединении, см. примечания к выпуску 9.3. Так что можно не указывать lateral здесь. - person Andomar; 04.05.2015