web-dev-qa-db-fra.com

Quelle est la bonne façon d'utiliser le module postgresql de node.js?

J'écris une application node.js sur Heroku et utilise le pg module . Je ne peux pas trouver le "bon" moyen d'obtenir un objet client pour chaque requête nécessaire pour interroger la base de données.

La documentation utilise un code comme celui-ci:

pg.connect(conString, function(err, client) {
  // Use the client to do things here
});

Mais vous n'avez sûrement pas besoin d'appeler pg.connect dans chaque fonction qui utilise la base de données, non? J'ai vu autre code qui fait ceci:

var conString = process.env.DATABASE_URL || "tcp://postgres:1234@localhost/postgres";
var client = new pg.Client(conString);
client.connect();
// client is a global so you can use it anywhere now

Je me penche vers la deuxième option car je pense que l'instance de base de données gratuite pour Heroku est limitée à une connexion de toute façon, mais y a-t-il des inconvénients à le faire de cette façon? Dois-je vérifier si mon objet client est toujours connecté à chaque fois avant de l'utiliser?

91
Philip

Je suis l'auteur de node-postgres . Tout d'abord, je m'excuse, la documentation n'a pas permis de préciser la bonne option: c'est de ma faute. Je vais essayer de l'améliorer. J'ai écrit n Gist tout à l'heure pour expliquer cela parce que la conversation est devenu trop long pour Twitter.

En utilisant pg.connect est le chemin à parcourir dans un environnement Web.

Le serveur PostgreSQL ne peut gérer qu'une requête à la fois par connexion. Cela signifie que si vous avez 1 global new pg.Client() connecté à votre backend, votre application entière est ignorée en fonction de la rapidité avec laquelle postgres peut répondre aux requêtes. Il va littéralement tout aligner, mettant en file d'attente chaque requête. Oui, c'est asynchrone et tout va bien ... mais ne préférez-vous pas multiplier votre débit par 10? Utilisation pg.connect met le pg.defaults.poolSize à quelque chose de sain (nous faisons 25-100, pas encore sûr du bon nombre).

new pg.Client est pour quand vous savez ce que vous faites. Lorsque vous avez besoin d'un seul client de longue durée pour une raison quelconque ou que vous avez besoin de contrôler très soigneusement le cycle de vie. Un bon exemple de ceci est l'utilisation de LISTEN/NOTIFY. Le client d'écoute doit être connecté et non partagé pour pouvoir gérer correctement les messages NOTIFY. Un autre exemple serait lorsque vous ouvrez un client ponctuel pour tuer des éléments bloqués ou dans des scripts en ligne de commande.

Une chose très utile est de centraliser tous les accès à votre base de données dans votre application dans un fichier. Ne pas jeter pg.connect _ appels ou nouveaux clients. Avoir un fichier comme db.js qui ressemble à ceci:

module.exports = {
   query: function(text, values, cb) {
      pg.connect(function(err, client, done) {
        client.query(text, values, function(err, result) {
          done();
          cb(err, result);
        })
      });
   }
}

De cette façon, vous pouvez changer votre implémentation de pg.connect à un groupe personnalisé de clients ou autre, et n’a à changer que les choses au même endroit.

Regardez le module node-pg-query qui ne fait que cela.

152
brianc

Je suis l'auteur de pg-promise , ce qui simplifie l'utilisation de node-postgres via des promesses.

Il aborde les problèmes de la bonne façon de se connecter et de se déconnecter de la base de données, en utilisant le pool de connexions implémenté par node-postgres , entre autres choses, comme les transactions automatisées.

Une demande individuelle dans pg-promise se résume à ce qui est pertinent pour votre logique métier:

db.any('SELECT * FROM users WHERE status = $1', ['active'])
    .then(data => {
        console.log('DATA:', data);
    })
    .catch(error => {
        console.log('ERROR:', error);
    });

c'est-à-dire que vous n'avez pas besoin de traiter la logique de connexion lors de l'exécution de requêtes, car vous ne configurez la connexion qu'une seule fois, globalement, comme ceci:

const pgp = require('pg-promise')(/*options*/);

const cn = {
    Host: 'localhost', // server name or IP address;
    port: 5432,
    database: 'myDatabase',
    user: 'myUser',
    password: 'myPassword'
};
// alternative:
// const cn = 'postgres://username:password@Host:port/database';

const db = pgp(cn); // database instance;

Vous pouvez trouver de nombreux autres exemples dans le didacticiel Apprendre par l'exemple , ou sur le page d'accueil du projet .

22
vitaly-t

Comme vous pouvez le constater à partir de la documentation , les deux options sont valables; choisissez donc celle que vous préférez. Comme vous, j'irais avec le deuxième choix.

0
alessioalex

Il est préférable de créer un pool pg globalement et chaque fois que vous devez effectuer une opération de base de données, utilisez le client, puis relâchez-le dans le pool. Une fois que toutes les opérations de base de données sont terminées, fermez le pool en utilisant pool.end()

Exemple de code -

let pool = new pg.Pool(dbConfig);
pool.connect(function(err, client, done) {

if (err) {
    console.error('Error connecting to pg server' + err.stack);
    callback(err);
} else {
    console.log('Connection established with pg db server');

    client.query("select * from employee", (err, res) => {

            if (err) {
                console.error('Error executing query on pg db' + err.stack);
                callback(err);
            } else {
                console.log('Got query results : ' + res.rows.length);


               async.each(res.rows, function(empRecord) {   
                        console.log(empRecord.name);
                });
            }
            client.release();

        });
}

});  

Pour plus de détails, vous pouvez vous référer à mon blog - Source

0
Aniket Thakur