PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Insert multi-rangées avec promesse pg

Je suis l'auteur de pg-promise.

Dans les anciennes versions de la bibliothèque, cela était couvert par des exemples simplifiés dans l'article Performance Boost, qui reste une bonne lecture lors de l'écriture d'applications de base de données hautes performances.

La nouvelle approche consiste à s'appuyer sur l'espace de noms des assistants, qui est finalement flexible et optimisé pour les performances.

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);

Voir API :ColumnSet, insérer.

Une telle insertion ne nécessite même pas de transaction, car si l'insertion d'un ensemble de valeurs échoue, aucune ne sera insérée.

Et vous pouvez utiliser la même approche pour générer l'une des requêtes suivantes :

  • INSERT sur une seule ligne
  • INSERT multi-lignes
  • UPDATE à une seule ligne
  • UPDATE multi-lignes

Les insertions utilisant la notation ${} sont-elles protégées contre l'injection sql ?

Oui, mais pas seul. Si vous insérez dynamiquement des noms de schéma/table/colonne, il est important d'utiliser des noms SQL, qui, combinés, protégeront votre code de l'injection SQL.

Question connexe :mises à jour multi-lignes PostgreSQL dans Node.js

extras

Q :Comment obtenir un id de chaque nouvel enregistrement en même temps ?

R : Simplement en ajoutant RETURNING id à votre requête, et en l'exécutant avec la méthode many :

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

ou mieux encore, récupérez les id-s et convertissez le résultat en tableau d'entiers, en utilisant la méthode map :

const res = await db.map(query, undefined, a => +a.id);
//=> [1, 2, ...]

Pour comprendre pourquoi nous avons utilisé + là, voir :pg-promise renvoie des entiers sous forme de chaînes.

MISE À JOUR-1

Pour insérer un grand nombre d'enregistrements, voir Importations de données.

MISE À JOUR-2

En utilisant la v8.2.1 et les versions ultérieures, vous pouvez encapsuler la génération de requête statique dans une fonction, afin qu'elle puisse être générée dans la méthode de requête, à rejeter lorsque la génération de requête échoue :

// 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);