Ответ 1
Я - автор pg-обещания.
В старых версиях библиотеки это было описано на упрощенных примерах в статье Performance Boost, которая по-прежнему важна для написания высокопроизводительных приложений баз данных.
Более новый подход заключается в использовании пространства имен помощников, которое в конечном итоге является гибким и оптимизировано для повышения производительности.
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, data = null
})
.catch(error => {
// error;
});
Такая вставка даже не требует транзакции, потому что, если один набор значений не может быть вставлен, ни один не будет вставлен.
И вы можете использовать тот же подход для генерации любого из следующих запросов:
- однорядный
INSERT
- многорядный
INSERT
- однорядный
UPDATE
- многорядный
UPDATE
Защищены ли вставки с использованием нотации $ {} от внедрения SQL?
Да, но не один. Если вы вставляете имена схем/таблиц/столбцов динамически, важно использовать имена SQL, что в сочетании защитит ваш код от внедрения SQL.
Смежный вопрос: Многострочные обновления PostgreSQL в Node.js
дополнительные
Q: Как получить id
каждой новой записи одновременно?
A: Просто добавьте RETURNING id
к вашему запросу и выполните его методом many:
const query = pgp.helpers.insert(values, cs) + 'RETURNING id';
const res = await db.many(query);
//=> [{id: 1}, {id: 2}, ...]
или, что еще лучше, получите идентификаторы и преобразуйте результат в массив целых чисел, используя метод map:
const res = await db.map(query, [], a => +a.id);
//=> [1, 2, ...]
Чтобы понять, почему мы использовали +
, см. pg-обещание возвращает целые числа в виде строк.
UPDATE-1
Для вставки огромного количества записей см. Импорт данных.
ОБНОВЛЕНИЕ 2-
Используя v8.2.1 и новее, вы можете заключить статическую генерацию запроса в функцию, чтобы ее можно было генерировать в методе запроса, чтобы отклонить при сбое генерации запроса:
// 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
});