Inserto multistrato con pg-promise

Vorrei inserire più righe con una singola query INSERT , ad esempio:

 INSERT INTO tmp(col_a,col_b) VALUES('a1','b1'),('a2','b2')... 

C’è un modo per farlo facilmente, preferibilmente per una serie di oggetti come questi:

 [{col_a:'a1',col_b:'b1'},{col_a:'a2',col_b:'b2'}] 

Potrei finire con 500 record in un blocco, quindi eseguire query multiple sarebbe indesiderabile.

Finora sono stato in grado di farlo solo per un singolo object:

 INSERT INTO tmp(col_a,col_b) VALUES(${col_a},${col_b}) 

Come una domanda a parte: gli inserimenti utilizzano la notazione ${} protetta contro le iniezioni SQL?

Sono l’autore di pg-promise .

Nelle versioni precedenti della libreria questo era coperto da esempi semplificati all’interno dell’articolo Performance Boost , che è ancora una lettura importante quando si scrivono applicazioni di database ad alte prestazioni.

L’approccio più recente consiste nell’affidarsi allo spazio dei nomi degli helper , che in ultima analisi è flessibile e altamente ottimizzato per le prestazioni.

 const pgp = require('pg-promise')({ /* initialization options */ capSQL: true // capitalize all generated SQL }); const db = pgp(/*connection*/); // our set of columns, to be created only once, and then shared/reused, // to let it cache up its formatting templates for high performance: const cs = new pgp.helpers.ColumnSet(['col_a', 'col_b'], {table: 'tmp'}); // data input values: const values = [{col_a: 'a1', col_b: 'b1'}, {col_a: 'a2', col_b: 'b2'}]; // generating a multi-row insert query: const query = pgp.helpers.insert(values, cs); //=> INSERT INTO "tmp"("col_a","col_b") VALUES('a1','b1'),('a2','b2') // executing the query: db.none(query) .then(data => { // success; }) .catch(error => { // error; }); 

Vedi API: ColumnSet , inserisci .

Un inserto di questo tipo non richiede nemmeno una transazione, perché se una serie di valori non viene inserita, nessuna verrà inserita.

E puoi utilizzare lo stesso approccio per generare una delle seguenti query:

  • INSERIMENTO a riga singola
  • INSERT più righe
  • UPDATE riga singola
  • UPDATE multi-fila

Gli inserimenti utilizzano la notazione $ {} protetta da SQL injection?

Sì, ma non da solo. Se si inseriscono dynamicmente nomi schema / tabella / colonna, è importante utilizzare nomi SQL , che in combinazione proteggeranno il codice dall’iniezione SQL.


Domanda correlata: aggiornamenti multi-riga di PostgreSQL in Node.js


extra

D: Come ottenere l’ id di ogni nuovo record allo stesso tempo?

A: Semplicemente aggiungendo RETURNING id alla tua query, ed eseguendo con metodo molti :

 const query = pgp.helpers.insert(values, cs) + 'RETURNING id'; db.many(query) .then(data => { // data = [{id: 1}, {id: 2}, ...] }) .catch(error => { // error; }); 

o ancora meglio, prendi l’id-s e converti il ​​risultato in un array di interi, usando la mappa dei metodi:

 db.map(query, [], a => +a.id) .then(data => { // data = [1, 2, ...] }) .catch(error => { // error; }); 

Per capire perché abbiamo usato + lì, vedi: pg-promise restituisce interi come stringhe .

UPDATE 1-

Per inserire un numero enorme di record, vedere Importazioni di dati .

UPDATE 2-

Utilizzando v8.2.1 e versioni successive, è ansible racchiudere la generazione di query statiche in una funzione, in modo che possa essere generata all’interno del metodo di query, per rifiutare quando la generazione della query ha esito negativo:

 // generating a multi-row insert query inside a function: const query = () => pgp.helpers.insert(values, cs); //=> INSERT INTO "tmp"("col_a","col_b") VALUES('a1','b1'),('a2','b2') // executing the query as a function that generates the query: db.none(query) .then(data => { // success; }) .catch(error => { // error; // will get here, even if the query generation fails });