2015-08-19 15 views
5

Ho una tabella Ordini dove devo conservare la sintesi di un ordine in una colonna di jsonbCercando nidificato serie jsonb in PostgreSQL

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

Ora voglio interrogare tutte users con il loro food->name.

Ho provato quanto segue, ma che mi dà anche all'utente foo, che non ha niente da mangiare .

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 

Come farei una tale richiesta?


UPDATE

ho anche un estivo come questo con due opzioni di cibo

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

e poi ottengo:

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

idealmente voglio ottenere

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

risposta

6

Va bene, se lo fai

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

si ottiene

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

Mettiamo questo selezionare all'interno di un altro, la selezione di quello che ci serve:

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) │ 
└───────────┴──────────┘ 

Siamo vicini. Abbiamo solo bisogno di aggiungere un 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; 

Con conseguente

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

Se si dispone di più dati nella propria matrice cibo come

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

Si può fare

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; 

E

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

Riscrivere la query sopra per usare espressioni di tabella comuni

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; 

Ora abbiamo solo bisogno di gruppo da 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; 

Risultato finale

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

Questo è il meglio che potevo venire con. Fammi sapere se trovi un modo migliore.

+0

thats great !, cosa succede se il cibo ha alcuni più elementi come "cibo": [{"nome": "test1", "prezzo": "100"}, {"nome": "colazione", "prezzo ":" 10 "}]' –

+0

@StefanMielke modificato –

+0

Perfetto! questo lo ha risolto –