2016-03-02 11 views
7

Attualmente ho il seguente codice per ottenere i risultati di due queryCome ottenere risultati da più query contemporaneamente con pg-promise?

dbro.many("SELECT geoname_id, country_name FROM paises WHERE locale_code=$1 LIMIT 10",data.lang) 
    .then(function(countriesData){ 
     data.countries=countriesData; 
     dbro.many("SELECT * FROM categorias") 
     .then(function(categoriesData){ 
     data.categories=(categoriesData) 
     console.log(data); 
     res.render('layout', data); 
     res.end(); 
     }) 
     .catch(function(err){ 
     console.log("error while fetching categories data"); 
     }) 
    }) 
    .catch(function(err){ 
     console.log("error while fetching countries data",err); 
    }); 

In qualche modo credo che questo non è giusto. Cosa succede se ho bisogno di ottenere i risultati di molte query prima di restituire il callback? L'annidamento di diversi poi/cattura diventa orribile. L'obiettivo è quello di avere tutti i dati pronti prima del rendering di una pagina (in Express)

risposta

17

pg-promise la documentazione ha plenty of examples di come eseguire più query.

inizializzazione

const pgp = require('pg-promise')(/* initialization options */); 
const db = pgp('postgres://username:[email protected]:port/database'); 

Quando query dipendono l'uno dall'altro che dovremmo loro concatenare entro un compito:

db.task('get-user-events', t => { 
     return t.one('select * from users where id = $1', 123) 
      .then(user => { 
       return t.any('select * from events where login = $1', user.name); 
      }); 
    }) 
    .then(data => { 
     // data = result from the last query; 
    }) 
    .catch(error => { 
     // error 
    }); 

Quando le query hanno dipendenze, abbiamo dovrebbe eseguirli come a batch all'interno di un'attività:

db.task('get-everything', t => { 
     return t.batch([ 
      t.any('select * from users'), 
      t.one('select count(*) from events') 
     ]); 
    }) 
    .then(data => { 
     // data[0] = result from the first query; 
     // data[1] = result from the second query; 
    }) 
    .catch(error => { 
     // error 
    }); 

E quando le query cambiano i dati, noi dovremmo sostituire task con tx per la transazione.

Si noti che ho sottolineato ogni istruzione con "dovrebbe", come è possibile eseguire tutto al di fuori di compiti o le operazioni, ma non è consigliato, a causa del modo in cui le connessioni al database sono gestiti.

È eseguire solo query sul protocollo radice (db oggetto) quando è necessario eseguire una singola query per richiesta HTTP. Più query allo stesso tempo devono essere eseguite sempre all'interno di attività/transazioni.

Vedi anche Chaining Queries, con il suo punto principale in fondo c'è:

Se non si segue l'approccio consigliato, l'applicazione deve eseguire meglio sotto un piccolo carico, a causa di più connessioni assegnate in parallelo, ma sotto un carico pesante svuoterà rapidamente il pool di connessioni, le prestazioni paralizzanti e la scalabilità della vostra applicazione.

UPDATE

A partire da pg-promise v7.0.0 possiamo tirare i risultati di più query in un unico comando, che è molto più efficiente di tutte le soluzioni precedenti:

db.multi('SELECT * FROM users;SELECT count(*) FROM events') 
    .then(data => { 
     // data[0] = result from the first query; 
     // data[1] = result from the second query; 
    }) 
    .catch(error => { 
     // error 
    }); 

O se si utilizza Bluebird, quindi:

db.multi('SELECT * FROM users;SELECT count(*) FROM events') 
    .spread((users, [{count}]) => { 
     // users = array of user records; 
     // count = string with the count; 
    }) 
    .catch(error => { 
     // error 
    }); 

Vedere i nuovi metodi multi e multiResult.

+0

Grazie, questo è quello che stavo cercando.Ho letto la documentazione ma ho perso la parte cruciale (almeno per me): \t // data [0] = risultato dalla prima query; // data [1] = risultato dalla seconda query; (dati risultanti come una matrice) –

+0

@ vitaly-t Grazie per i vostri esempi. Tuttavia, come andresti se dovessi mescolare entrambi? Nel mio compito eseguo 5 query indipendenti. Ognuno restituisce l'ultimo ID di inserimento. Una volta eseguita questa attività, ho bisogno di eseguire un'ultima query, che utilizzerebbe tutti gli ID prodotti dall'attività. Non sono riuscito a mescolare entrambi finora. Hai qualche idea. Grazie per l'aiuto. – Stanislasdrg

+0

@Stanislasdrg quello che stai chiedendo è più sull'uso di base delle promesse piuttosto che su questa libreria. Si restituisce t.batch ([... i 5 inserti ...]). Quindi (data => t.query (... query basata sui dati ...)) '. –

Problemi correlati