1

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

1
  • Please include the relevant sample data and table definitions in your question as formatted text. Outside links don't always work (for me SQLFiddle hardly ever works, it always hangs) Commented Oct 15, 2019 at 6:54

3 Answers 3

1

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)

Sign up to request clarification or add additional context in comments.

Comments

0

It is not quite clear to me what is your expected output. But to find the cities with o in Asia is like that:

demo:db<>fiddle

SELECT 
    * 
FROM 
    people,
    jsonb_array_elements(travel -> 'trips') elems
WHERE
    elems ->> 'city' LIKE '%o%'
    AND elems ->> 'continent' = 'Asia'
  1. Expand the array elements into one row each
  2. Filter by continent and city

2 Comments

S-Man, thanks for your answer, To be more specific, let's ask who travelled to Europe and what are the trips? I'd like to construct the reply as below; [ { "name": "Lucy", "trips": [ { "continent": "Europe", "city": "Paris" }, { "continent": "Europe", "city": "London" } ] }, { "name": "Tom", "trips": [ { "continent": "Europe", "city": "Frankfurt" }, { "continent": "Europe", "city": "London" } ] } ]
What about this? dbfiddle.uk/…
0

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"}]'

1 Comment

Europe or Asia (as in your question)?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.