2011-10-26 5 views
4

J'essaye de faire une insertion ou une mise à jour dans une base de données postgres en utilisant node.js avec l'extension pg (version 0.5.4).Upsert dans Postgres utilisant node.js

Jusqu'à présent, j'ai ce code: (...)

client.query({ 
      text: "update users set is_active = 0, ip = $1 where id=$2", 
      values: [ip,id] 
     }, function(u_err, u_result){ 
      debug(socket_id,"update query result: ",u_result); 
       debug(socket_id,"update query error: ",u_err); 

        date_now = new Date(); 
      var month = date_now.getMonth() + 1; 

      if(!u_err){ 

       client.query({ 
        text: 'insert into users (id,first_name,last_name,is_active,ip,date_joined) values' + 
        '($1,$2,$3,$4,$5,$6)', 
        values: [ 
          result.id, 
          result.first_name, 
          result.last_name, 
          1, 
          ip, 
          date_now.getFullYear() + "-" + month + "-" + date_now.getDate() + " " + date_now.getHours() + ":" + date_now.getMinutes() + ":" + date_now.getSeconds() 
          ] 
       }, function(i_err, i_result){ 
        debug(socket_id,"insert query result: ",i_result); 
        debug(socket_id,"insert query error: ",i_err); 
       }); 
      } 
     }); 

Le problème est que, bien que les deux requêtes fonctionnent le problème est toujours en cours d'exécution à la fois au lieu de fonctionner la fonction d'insertion si la mise à jour échoue .

Les fonctions de débogage en sortie de code quelque chose comme:

MISE À JOUR

Object { type="update query result: ", debug_value={...}} 
home (linha 56) 
Object { type="update query error: ", debug_value=null} 
home (linha 56) 
Object { type="insert query result: "} 
home (linha 56) 
Object { type="insert query error: ", debug_value={...}} 

Insérer

Object { type="update query result: ", debug_value={...}} 
home (linha 56) 
Object { type="update query error: ", debug_value=null} 
home (linha 56) 
Object { type="insert query result: ", debug_value={...}} 
home (linha 56) 
Object { type="insert query error: ", debug_value=null} 

** EDIT **

ANSWE R FROM développeur noeud-postgres:

Il est possible de récupérer le nombre de lignes affectées par une insertion et la mise à jour . Il n'est pas entièrement implémenté dans les liaisons natives, mais fonctionne dans la version javascript pure. Je vais travailler sur cela dans le la semaine prochaine ou deux. Dans le même temps utiliser la version javascript pur et un coup d'oeil ici:

https://github.com/brianc/node-postgres/blob/master/test/integration/client/result-metadata-tests.js

** FIN EDIT **

Quelqu'un peut-il aider?

Répondre

2

La réponse immédiate à votre question est d'utiliser une procédure stockée pour faire un upsert.

http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE

Quelque chose comme cela fonctionne très bien avec le module p.

client.query({ 
    text: "SELECT upsert($1, $2, $3, $4, $5, $6)" 
    values: [ obj.id, 
      obj.first_name, 
      obj.last_name, 
      1, 
      ip, 
      date_now.getFullYear() + "-" + month + "-" + date_now.getDate() + " " + date_now.getHours() + ":" + date_now.getMinutes() + ":" + date_now.getSeconds() 
      ] 
}, function(u_err, u_result){ 
    if(err) // this is a real error, handle it 

    // otherwise your data is updated or inserted properly 
}); 

Bien sûr, cela suppose que vous utilisez une sorte d'objet de modèle qui a toutes les valeurs dont vous avez besoin, même si elles ne changent pas. Vous devez les passer tous dans l'upsert. Si vous êtes bloqué comme vous l'avez montré ici, vous devriez probablement vérifier l'objet d'erreur après la mise à jour pour déterminer s'il a échoué parce que la ligne est déjà là, ou pour une autre raison (qui est une vraie erreur de db doit être manipulé).

Ensuite, vous devez faire face à la situation de concurrence potentielle entre le moment où votre mise à jour a échoué et le moment où votre insertion passe. Si une autre fonction essaie d'insérer avec le même identifiant, vous avez un problème. Les transactions sont bonnes pour cela. C'est tout ce que j'ai en ce moment. J'espère que cela aide.

+0

Salut Marco !! Merci d'avoir répondu! Je suis entré en contact avec le développeur de pg module pour node.js et j'ai édité la question pour mettre en vedette sa réponse! En ce qui concerne votre réponse, c'était mon intention initiale, mais comme je développe en utilisant heroku et que j'ai besoin de taps pour migrer la base de données, j'ai un problème car je pense que les taps ne peuvent pas exporter les procédures stockées. (Je peux me tromper cependant) de toute façon pouvez-vous m'éclairer sur les problèmes de performance sur les procédures stockées? A propos des problèmes de concurrence, je ne pense pas qu'ils s'appliquent, mais si vous pouviez poster un lien vers ilustrate Transictions, ce serait parfait ...;) Merci encore une fois !! – jribeiro

2

J'ai rencontré ce problème lors de la connexion à une instance PG à l'aide de JDBC. La solution que je fini par utiliser est:

UPDATE table SET field='C', field2='Z' WHERE id=3; 
INSERT INTO table (id, field, field2) 
     SELECT 3, 'C', 'Z' 
     WHERE NOT EXISTS (SELECT 1 FROM table WHERE id=3); 

La mise à jour ne fait rien si le dossier n'existe pas et l'insert ne fait rien si le dossier existe.Cela fonctionne plutôt bien et est une solution SQL par rapport à une procédure stockée.

est ici la question initiale: Insert, on duplicate update in PostgreSQL?

+0

J'ai effectivement mis en place quelque chose dans ce sens aussi. Mais je teste la réponse de la première requête et ne lance le second que si aucune ligne n'a été affectée. Ceci est/était seulement supporté dans le mode natif js du https://github.com/brianc/node-postgres qui est ce que j'utilise. Merci d'avoir pris le temps de répondre!! – jribeiro

Questions connexes