[Python] Psycopg2 e serializzazione delle SELECT in JSON
Daniele Varrazzo
piro a develer.com
Gio 16 Ott 2014 16:32:41 CEST
On 2014-10-16 15:08, Alberto Granzotto wrote:
> Ciao Daniele, grazie per la esaustiva risposta, mi sembra tutto chiaro
> a
> parte una cosa ->
>
> 2014-10-16 15:47 GMT+02:00 Daniele Varrazzo <piro a develer.com>:
>
>> On 2014-10-16 13:59, Alberto Granzotto wrote:
>> [...]l as (id integer, email text);
>>
>> e riscrivi la tua query in maniera da resitiuire un array di questi
>> tipi:
>> test=> select u.id, u.name, array_agg((e.id, e.email)::t_email) from
>> users u join emails e on u.id = e.user_id group by 1,2;
>>
>
> C'è modo di evitare il group by? O devo prima estrarmi tutti gli id
> delle
> email associate allo specifico user e poi usarle nel group by? Cosa
> succede
> se invece di estrarre un solo user volessi estrarre N user?
Il group by e' necessario per usare array_agg: se non lo usi hai i dati
di ogni utente ripetuti se un utente ha piu' di una email (come nella
tua query originale). Puoi usare una sottoquery che crea una mappa
id_utente -> array di t_email e fare il join di questa con gli utenti,
ma un group by (sebbene piu' efficiente) ci vuole sempre, es. nella
sottoquery.
In linea generale, psycopg ti restituira' un oggetto per ogni record che
Postgres genera: i gradi di liberta' sono nel record generato da
postgres (quindi e.g. usare group by, creare array, strutture,
dizionari, ecc. usando i tipi di postgres in maniera un po' piu'
avanzata) e nel configurare il mapping tra i record letti e gli oggetti
python creati da psycopg (giocando con i typecaster). Se esci da questo
framework (un record -> un oggetto) allora devi fare qualcosa a valle di
psycopg, quindi ti ritrovi con i tipi di algoritmi ripetitivi per cui
hai scritto la mail in primo momento: iterare sugli utenti, controllare
se li avevi gia' letti, metterli in un dict con una lista di email
vuote, aggiungere una email...
Quindi, detto questo, come mai vuoi evitare il group by? Ti aspetti di
leggere i dati da postgres in una maniera che non ho capito (nel qual
caso fammi un esempio) oppure ti aspetti un comportamento di psycopg che
esula dal restitiure un oggetto per ogni record?
Estrarre N utenti si fa esattamente come sopra: la query restituisce un
record per utente, ognuno con la lista delle sue email, e puoi iterare
sul cursore in tutti i modi che psycopg offre (fetchmany(), fetchall(),
for record in cur:...)
test=> insert into users (name) values ('daniele');
INSERT 0 1
test=> insert into emails (user_id, email) values (2,
'piro a officine');
INSERT 0 1
test=> insert into emails (user_id, email) values (2,
'piro a develer');
INSERT 0 1
In [20]: dcur.execute("select u.id, u.name, array_agg((e.id,
e.email)::t_email) as emails from users u join emails e on u.id =
e.user_id group by 1,2")
In [21]: dcur.fetchall()
Out[21]:
[{'emails': [
{'email': 'alberto a example.org', 'id': 1},
{'email': 'alberto a lemonparty.org', 'id': 2}],
'id': 1,
'name': 'alberto'},
{'emails': [
{'email': 'piro a officine', 'id': 4},
{'email': 'piro a develer', 'id': 5}],
'id': 2,
'name': 'daniele'}]
-- Daniele
Maggiori informazioni sulla lista
Python