2015-08-19 2 views
5

У меня есть таблица заказов, где я хранить сводку заказа в jsonb колонкиSearching вложенной jsonb массива в PostgreSQL

{"users": [ 
    {"food": [{"name": "dinner", "price": "100"}], "room": "2", "user": "bob"}, 
    {"room": "3", "user": "foo"} 
]} 

Теперь я хочу, чтобы запросить все users с их food->name.

Я попытался следующие, но это дает мне также пользователю Foo, что не имеет никакой пищи .

select 
    jsonb_array_elements(jsonb_array_elements(summary->'users')->'food')->>'name' as food, 
    jsonb_array_elements(summary->'users')->>'user' as user_name 
from orders; 

food | user_name 
-------+----------- 
dinner | bob 
dinner | foo 

Как бы я сделал такой запрос?


UPDATE

У меня есть также летний, как это с двумя вариантами пищевых

{"users": [ 
    {"food": [{"name": "dinner", "price": "100"}, {"name": "breakfast", "price": "100"}], "room": "2", "user": "bob"}, 
    {"room": "3", "user": "foo"} 
]} 

и чем я получаю:

food | user_name 
-----------+----------- 
dinner | bob 
breakfast | foo 

идеале я хочу, чтобы получить

food    | user_name 
----------------------+----------- 
dinner, breakfast | bob 

ответ

6

Хорошо, если вы

SELECT jsonb_array_elements(summary->'users') as users FROM orders; 

вы получите

┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 
│              users              │ 
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ 
│ {"food": [{"name": "dinner", "price": "100"}, {"name": "breakfast", "price": "50"}], "room": "2", "user": "bob"} │ 
│ {"room": "3", "user": "foo"}                      │ 
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 

Давайте поставим этот выбор внутри другой, выбирая то, что нам нужно:

SELECT users->'user' as user_name, users->'food'->0->'name' as food FROM (
    SELECT jsonb_array_elements(summary->'users') as users FROM orders 
) as s; 

┌───────────┬──────────┐ 
│ user_name │ food │ 
├───────────┼──────────┤ 
│ "bob"  │ "dinner" │ 
│ "foo"  │ (null) │ 
└───────────┴──────────┘ 

Мы близки. Нам просто нужно добавить WHERE.

SELECT users->'user' as user_name, users->'food'->0->'name' as food FROM (
    SELECT jsonb_array_elements(summary->'users') as users FROM orders 
) as s WHERE (users->'food') is not null; 

Результирующее в

┌───────────┬──────────┐ 
│ user_name │ food │ 
├───────────┼──────────┤ 
│ "bob"  │ "dinner" │ 
└───────────┴──────────┘ 

Если у вас есть данные в массиве еды как

'{"users": [{"food": [{"name": "dinner", "price": "100"}, {"name" : "breakfast", "price" : "50"}], "room": "2", "user": "bob"}, {"room": "3", "user": "foo"}]}' 

Вы можете сделать

SELECT users->'user' as user_name, jsonb_array_elements(users->'food')->>'name' as food FROM (
    SELECT jsonb_array_elements(summary->'users') as users FROM orders 
) as s WHERE (users->'food') is not null; 

И

┌───────────┬───────────┐ 
│ user_name │ food │ 
├───────────┼───────────┤ 
│ "bob"  │ dinner │ 
│ "bob"  │ breakfast │ 
└───────────┴───────────┘ 

Переписывая выше запрос использовать Common Table Expressions

WITH users_data AS (
    SELECT jsonb_array_elements(summary->'users') as users FROM orders 
), user_food AS (
    SELECT users->'user' as user_name, jsonb_array_elements(users->'food')->>'name' as food 
    FROM users_data 
    WHERE (users->'food') is not null 
) SELECT * FROM user_food; 

Теперь нам нужно сгруппировать по user_name

WITH users_data AS (
    SELECT jsonb_array_elements(summary->'users') as users FROM orders 
), user_food AS (
    SELECT users->'user' as user_name, jsonb_array_elements(users->'food')->>'name' as food 
    FROM users_data 
    WHERE (users->'food') is not null 
) SELECT user_name, array_agg(food) foods FROM user_food GROUP BY user_name; 

Окончательный результат

┌───────────┬────────────────────┐ 
│ user_name │  foods  │ 
├───────────┼────────────────────┤ 
│ "bob"  │ {dinner,breakfast} │ 
└───────────┴────────────────────┘ 

Это лучшее, что я мог бы придумайте. Дайте мне знать, если вы найдете лучший способ.

+0

Это здорово !, если в еде есть еще несколько элементов, таких как «еда»: [{«name»: «test1», «price»: «100»}, {«name»: «завтрак», «цена» ":" 10 "}]' –

+0

@StefanMielke отредактировал –

+0

Отлично! что это разрешило –