JSONB запрос postgresql по внутреннему свойству - PullRequest
1 голос
/ 15 октября 2019

Я использую postgresql 10.6. В моей таблице есть столбец jsonb travel, заполненный приведенными ниже образцами данных. Ниже приведено sqlfiddle:

http://sqlfiddle.com/#!17/e52ff/1

Мой стол:

id | travel                                                                                                                                                                                                   
-: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1 | {"name": "Lucy", "trips": [{"city": "Tokyo", "continent": "Asia"}, {"city": "Bangkok", "continent": "Asia"}, {"city": "Paris", "continent": "Europe"}, {"city": "London", "continent": "Europe"}]}       
 2 | {"name": "Tom", "trips": [{"city": "Tokyo", "continent": "Asia"}, {"city": "Kyoto", "continent": "Asia"}, {"city": "Frankfurt", "continent": "Europe"}, {"city": "London", "continent": "Europe"}]}      
 3 | {"name": "Lenny", "trips": [{"city": "Tokyo", "continent": "Asia"}, {"city": "Bangkok", "continent": "Asia"}, {"city": "New York", "continent": "America"}, {"city": "Seattle", "continent": "America"}]}

DDL и введите код:

create table people (
    id serial primary key,
    travel jsonb
);

insert into people (travel) values (
'{
    "name": "Lucy",
    "trips": [
      {
        "continent": "Asia",
        "city": "Tokyo"
      },
      {
        "continent": "Asia",
        "city": "Bangkok"
      },
      {
        "continent": "Europe",
        "city": "Paris"
      },
      {
        "continent": "Europe",
        "city": "London"
      }
    ]
  }
'::jsonb);

insert into people (travel) values (
'{
    "name": "Tom",
    "trips": [
      {
        "continent": "Asia",
        "city": "Tokyo"
      },
      {
        "continent": "Asia",
        "city": "Kyoto"
      },
      {
        "continent": "Europe",
        "city": "Frankfurt"
      },
      {
        "continent": "Europe",
        "city": "London"
      }
    ]
  }
'::jsonb);

insert into people (travel) values (
'{
    "name": "Lenny",
    "trips": [
      {
        "continent": "Asia",
        "city": "Tokyo"
      },
      {
        "continent": "Asia",
        "city": "Bangkok"
      },
      {
        "continent": "America",
        "city": "New York"
      },
      {
        "continent": "America",
        "city": "Seattle"
      }
    ]
  }
'::jsonb);

Какмогу ли я запросить информацию о поездках в города с буквой "o" на континенте Азия ?

Спасибо и всего наилучшего

Ответы [ 3 ]

1 голос
/ 16 октября 2019

Я думаю, что ваш собственный ответ просто отлично. Выбор массива может быть немного упрощен, а дублирование условия фильтра континента немного уродливо - я бы написал:

SELECT *
FROM (
  SELECT
    travel -> 'name' as name,
    ARRAY(
      SELECT mytrips
      FROM jsonb_array_elements(travel -> 'trips') mytrips
      WHERE mytrips ->> 'continent' = 'Europe'
    ) as trips
  FROM
    people
  ) t
WHERE 
  trips <> '{}'

( онлайн-демонстрация )
С другой стороны, если у вас есть индекс для travel, оператор @> в предложении WHERE может быть быстрее.

Возможно, проще, но с другой семантикой относительно несколькихпоездки одного и того же человека, будет групповой подход:

SELECT travel -> 'name' as name, jsonb_agg(trip) as trips
FROM people, jsonb_array_elements(travel -> 'trips') trip
WHERE trip ->> 'continent' = 'Europe'
GROUP BY name

( онлайн демо )

0 голосов
/ 16 октября 2019

Я мог бы получить результат, как я хочу, с помощью запроса ниже. Однако я не уверен, что это оптимально с точки зрения производительности. Любое предложение, чтобы заставить его работать лучше?

SELECT
  travel -> 'name',   
   Array(      
      (SELECT elements.mytrips FROM
       (SELECT jsonb_array_elements(travel -> 'trips') as mytrips) as elements  
       WHERE elements.mytrips ->> 'continent' = 'Europe'
      )     
    )   
FROM 
  people
WHERE 
  travel -> 'trips' @> '[{"continent": "Europe"}]'
0 голосов
/ 15 октября 2019

Мне не совсем понятно, каков ваш ожидаемый результат. Но найти города с o в Asia так:

demo: db <> fiddle

SELECT 
    * 
FROM 
    people,
    jsonb_array_elements(travel -> 'trips') elems
WHERE
    elems ->> 'city' LIKE '%o%'
    AND elems ->> 'continent' = 'Asia'
  1. Развернуть массивэлементы в одну строку каждый
  2. Фильтр по continent и city
...