I'm using postgresql 10.6. My table has a jsonb column travel
filled with below sample data. Below is the sqlfiddle;
http://sqlfiddle.com/#!17/e52ff/1
My table:
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 and insert code:
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);
How can I query the travels to cities which has "o" letter in it, in continent Asia ?
Thanks & regards
I think your own answer is just fine. The array selection can be a bit simplified, and the duplication of the continent filter condition is a bit ugly - I would probably write
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 <> '{}'
( online demo )
On the other hand, if you do have an index on travel
, the @>
operator in the WHERE
clause might be faster.
Possibly simpler, but with different semantics regarding multiple trips by the same person, would be a grouping approach:
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
( online demo )
It is not quite clear to me what is your expected output. But to find the cities with o
in Asia
is like that:
SELECT
*
FROM
people,
jsonb_array_elements(travel -> 'trips') elems
WHERE
elems ->> 'city' LIKE '%o%'
AND elems ->> 'continent' = 'Asia'
continent
and city
I could obtain the result as I want with the below query. However, I'm not sure if it's optimal in terms of performance. Any suggestion to make it perform better?
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"}]'
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.