Eu sou o autor de pg-promise.
Nas versões mais antigas da biblioteca, isso era coberto por exemplos simplificados no artigo Performance Boost, que ainda é uma boa leitura ao escrever aplicativos de banco de dados de alto desempenho.
A abordagem mais recente é contar com o namespace helpers, que é flexível e otimizado para desempenho.
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 (statically), and then 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:
await db.none(query);
Consulte API:ColumnSet, inserir.
Essa inserção nem mesmo requer uma transação, porque se um conjunto de valores não for inserido, nenhum será inserido.
E você pode usar a mesma abordagem para gerar qualquer uma das seguintes consultas:
- linha única
INSERT
INSERT
de várias linhasUPDATE
de linha únicaUPDATE
de várias linhas
As inserções usando a notação ${} são protegidas contra injeção de sql?
Sim, mas não sozinho. Se você estiver inserindo nomes de esquema/tabela/coluna dinamicamente, é importante usar nomes SQL, que em combinação protegerão seu código contra injeção de SQL.
Pergunta relacionada:atualizações de várias linhas do PostgreSQL no Node.js
extras
P:Como obter o
id
de cada novo registro ao mesmo tempo? R: Simplesmente anexando
RETURNING id
para sua consulta e executando-a com o método many:const query = pgp.helpers.insert(values, cs) + ' RETURNING id';
const res = await db.many(query);
//=> [{id: 1}, {id: 2}, ...]
ou melhor ainda, pegue o id-s e converta o resultado em array de inteiros, usando o método map:
const res = await db.map(query, undefined, a => +a.id);
//=> [1, 2, ...]
Para entender por que usamos
+
lá, veja:pg-promise retorna inteiros como strings. ATUALIZAÇÃO-1
Para inserir um grande número de registros, consulte Importações de dados.
ATUALIZAÇÃO-2
Usando a v8.2.1 e posterior, você pode agrupar a geração de consulta estática em uma função, para que ela possa ser gerada dentro do método de consulta, para rejeitar quando a geração de consulta falhar:
// 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:
await db.none(query);