Node.js异步|从api插入postgresql数据库结果

时间:2013-11-19 20:51:56

标签: node.js postgresql asynchronous insert

我是node.js的新手。我想要实现的目标如下:

  1. 连接到我的postgresql数据库,获取一个地方的信息(id,coordinates)。
  2. 使用上一步中获得的坐标调用天气api并获取该点的信息。
  3. 将返回的json插入数据库中。我得到8个小时的物体,每3小时有一次天气信息(0,3,6,9,12,15,18,21)。我需要遍历这些对象并将它们存储在数据库中的8条记录中。
  4. 我写了以下代码:

    app.get('/getapi', function(req, res){
    var json_bbdd;  
     //------------ BBDD CONNECTION----------------
                var pg = require('pg'); 
                var conString = "postgres://postgres:postgres2@localhost/places";
    
                var client = new pg.Client(conString);
                client.connect(function(err) {
                  if(err) {
                     console.log('could not connect to postgres');
                  }
                  client.query('SELECT * from places where id=3276', function(err, result) {
                    if(err) {
                     console.log('error running query'); 
                    }
                    json_bbdd=result.rows[0];
    
                    var coords = JSON.parse(json_bbdd.json).coordinates;
                    var id = json_bbdd.id;
                    var input = {
                        query: coords[1] + ',' + coords[0] ,
                        format: 'JSON',
                        fx: '',
                        callback: 'MarineWeatherCallback'
                    };
    
    
                    var url = _PremiumApiBaseURL + "marine.ashx?q=" + input.query + "&format=" + input.format + "&fx=" + input.fx + "&key=" + _PremiumApiKey + "&tide=yes";
    
                    $.ajax({
                    type: 'GET',
                    url: url,
                    async: false,
                    contentType: "application/json",
                    dataType: 'jsonp',
                    success: function (json) {
    
                        var date= json.data.weather[0].date;
    
                              for (var i=0; i < 8; i++){
    
                              var hourly = json.data.weather[0].hourly[i];
                              var time= hourly.time;
    
                                client.query('INSERT into parte (id, date, time) VALUES($1, $2, $3)', [id, date, time], 
                                function(err, result) {
                                    if (err) {
                                        console.log(err);
                                    } else {
                                        console.log('row inserted: ' + id + ' ' + time);
                                    }
    
                                }); 
    
                              } // FOR
    
                        },
                        error: function (e) {
                            console.log(e.message);
                        }
                    });
    
                    client.end();
                  });
                });
    });
    

    完美地执行步骤1和2。另一方面,第三步没有做任何事情,甚至没有抛出错误。

    我在这篇文章中读到:node-postgres will not insert data, but doesn't throw errors either使用异步模块可以提供帮助,但我不知道如何重写代码。我需要一些帮助。

    此致 的Aitor

2 个答案:

答案 0 :(得分:2)

我没有测试你的片段,我只能用你眼前看起来不好的东西来帮助你。

  1. 最好不要在节点服务器上使用jQuery。有一个名为request的优秀库可以进行远程http请求。
  2. 您应该更好地处理数据库错误,因为在您的示例中,您的代码将在数据库错误后继续。
  3. 您过早地调用client.end(),当您尝试将数据插入数据库时​​,连接已经关闭。您必须在成功和错误函数结束时移动client.end()并等待所有回调完成。
  4. 我认为最好使用连接池而不是Client
  5. 您可以在PostgreSQL中使用JSON类型,以避免在代码中序列化/反序列化JSON数据。
  6. 这是修改后的示例(未经测试)。我没有在这里替换jQuery,包括一些小调整。

    var pg = require('pg'); 
    var conString = "postgres://postgres:postgres2@localhost/places";
    
    app.get('/getapi', function(req, res, next){
    var json_bbdd;  
    //------------ BBDD CONNECTION----------------
    
      pg.connect(conString, function(err, client, done) {
        if(err) {
          // example how can you handle errors
          console.error('could not connect to postgres');
          return next(new Error('Database error'));
        }
        client.query('SELECT * from places where id=3276', function(err, result) {
          if(err) {
            console.error('error running query');
            done();
            return next(new Error('Database error'));
          }
    
          json_bbdd = result.rows[0];
    
          var coords = JSON.parse(json_bbdd.json).coordinates;
          var id = json_bbdd.id;
          var input = {
            query: coords[1] + ',' + coords[0] ,
            format: 'JSON',
            fx: '',
            callback: 'MarineWeatherCallback'
          };
    
    
          var url = _PremiumApiBaseURL + "marine.ashx?q=" +
                    input.query + "&format=" + input.format +
                    "&fx=" + input.fx + "&key=" +
                    _PremiumApiKey + "&tide=yes";
    
          $.ajax({
            type: 'GET',
            url: url,
            async: false,
            contentType: "application/json",
            dataType: 'jsonp',
            success: function (json) {
    
              var date = json.data.weather[0].date;
              var callbacks = 0;
    
              for (var i=0; i < 8; i++) {
    
                var hourly = json.data.weather[0].hourly[i];
                var time= hourly.time;
    
                client.query(
                  'INSERT into parte (id, date, time) VALUES($1, $2, $3)',
                  [id, date, time], 
                  function(err, result) {
                    if (err) {
                      console.log(err);
                    } else {
                      console.log('row inserted: ' + id + ' ' + time);
                    }
                    callbacks++;
                    if (callbacks === 8) {
                      console.log('All callbacks done!');
                      done();    // done(); is rough equivalent of client.end();
                    }
                }); 
    
              } // FOR
            },
            error: function (e) {
               console.error(e.message);
               done();    // done(); is rough equivalent of client.end(); 
               return next(new Error('Http error'));
            }
          });
        });
      });
    });
    

答案 1 :(得分:0)

好的,现在又遇到了另一个问题......我怀疑创建了一个新帖子,但我认为这可能与之前的帖子有关。

目的是从数据库中读取而不是一个地方3个地方,并为每个地方执行与之前相同的过程。 代码如下(由ivoszz提出的更改):

app.get('/getapi', function(req, res, next){  
//------------ BBDD CONNECTION----------------

  pg.connect(conString, function(err, client, done) {
    if(err) {
      // example how can you handle errors
      console.error('could not connect to postgres',err);
      return next(new Error('Database error'));
    }
    client.query('SELECT * from places where id>3274 and id<3278', function(err, result) {
      if(err) {
        console.error('error running query',err);
        done();
        return next(new Error('Database error'));
      }

      var first_callback = 0;
      for (var y=0;  y<result.rows.length; y++) {
          var coords = JSON.parse(result.rows[y].json).coordinates;
          var id = result.rows[y].id;
          var input = {
            query: coords[1] + ',' + coords[0] ,
            format: 'JSON',
            fx: ''
          };

          var url = _PremiumApiBaseURL + "marine.ashx?q=" + input.query + "&format=" + input.format + "&fx=" + input.fx + "&key=" + _PremiumApiKey;

          request(url, function(err, resp, body) {
            body = JSON.parse(body);
            if (!err && resp.statusCode == 200) {

              var date = body.data.weather[0].date;
              var callbacks = 0;

              for (var i=0; i < 8; i++) {


                var hourly = body.data.weather[0].hourly[i];

                client.query(
                  'INSERT into parte (id, date, time) VALUES($1, $2, $3)',
                  [id, date, hourly.time], 
                  function(err, result) {
                    if (err) {
                      console.log(err);
                    } else {
                      console.log('row inserted: ' + id + ' iteration ' + i);
                    }
                    callbacks++;
                    if (callbacks === 8) {
                      console.log('All callbacks done!from id '+id);
                      //done();    // done(); is rough equivalent of client.end();
                      //res.send("done");
                    }
                }); 

              } // FOR
            }
            else { // if the API http request throws an error
               console.error(err);
               done();    // done(); is rough equivalent of client.end(); 
               return next(new Error('Http API error'));
            } 
          }); // REQUEST API URL

      first_callback++;
      if (first_callback === result.rows.length-1) {
        console.log('All global callbacks done!');
        done();    // done(); is rough equivalent of client.end();
        res.send("done");
      }} 
    }); // SELECT from pg
  }); // CONNECT to pg
}); // app.get

我不知道为什么它试图插入id = 3277三次而不是插入id = 3275,id = 3276然后id = 3277 ......它的作用是:它插入前8条记录ok第一次(id = 3277),但它会抛出一个错误,说已经插入了记录(主键= id,日期,时间),ID为3277 ......

似乎首先执行第一个FOR的3次迭代,然后执行第二次FOR的3次迭代,但是使用最后一次迭代(地点)的信息。我无法理解它......