【问题标题】:Node.js | insert into postgresql database results from apiNode.js |从 api 插入 postgresql 数据库结果
【发布时间】:2013-12-05 03:30:24
【问题描述】:

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

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

我写了以下代码:

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 次迭代,但使用最后一次迭代(位置)的信息。不是很懂。。。

【问题讨论】:

  • 你在哪里看到它试图插入 id 3277 三次?你问这个问题时有没有漏掉什么?
  • 我通过代码写了一些console.logs,看看它在做什么以及以什么顺序发生了什么
  • 我想了这么多,我只是想提请你注意,如果你想提一些你应该在你的问题正文中包含该信息的内容。我的回答可能会对您的问题有所启发。

标签: database node.js postgresql for-loop insert


【解决方案1】:

您遇到了一些在新 JavaScript 开发人员中常见的独特范围问题。您必须意识到的第一件事是 JavaScript 范围绑定到一个函数,尤其是定义它的函数。如果您在另一个函数内部定义一个函数,那么您也有效地将该函数绑定到当前函数的范围.这会导致奇怪的行为。例如:

var someMsg = "Hello, World"; // English

var showMsg = function() {
  console.log(someMsg);
};

setTimeout(showMsg, 2000); // Fire off after 2 seconds
someMsg = "Hola, Mundo"; // Spanish

您将看到打印的是"Hola, Mundo",您可能(忍受这个人为的例子)一直期待"Hello, World"。有三个简单的解决方案 - 第一个是将值作为参数传递给函数:

var showMsg = function(msg) {
  // ...
};

第二个是提供一个包装器来限定这些变量。这个包装器可以是一个 IIFE,因为您不需要直接访问它。

var someMsg = "Hello, World";

(function(someMsg) {
  setTimeout(function() {
    console.log(showMsg);
  }, 2000);
)(someMsg);

someMsg = "Hola, Mundo";

现在输出与我们预期的完全一样,"Hello, World",我们通过在执行 IIFE 时使用包含当前值的参数隐藏原始值(仅因为相同的变量名)来实现此目的。因此,当我们稍后更改外部someMsg 的值时,它不会更改IIFE 内部someMsg 的值。由于像这样的复杂调用的嵌套函数,这在 JavaScript 中循环值时很有用(并且是必需的)。

您的示例(高度简化)是:

// Do some stuff
for (var y=0;  y<result.rows.length; y++) {
  // ...
  var id = result.rows[y].id;

  (function(recordId) {
    // The current body of this for loop that requires id
  })(id);
}
// More stuff

如果您注意到,在最后一个示例中,我没有使用 id 作为参数名称,我倾向于这样做是为了防止混淆或进一步阐明内部函数值的用途。

最终的解决方案是使用函数来构建具有特定范围的函数。你可以定义你的生成器:

var generateShowFn = function(someMsg) {
  return function() {
    console.log(someMsg);
  };
};

var someMsg = "Hello, World";

setTimeout(generateShowFn(someMsg), 2000);

someMsg = "Hola, Mundo";

您仍然会得到正确的结果。与前两种方法相比,我更喜欢这种方法,因为它允许我在对象内部编写回调代码,作为进程中的另一个成员函数或逻辑步骤。这也减少了“嵌套地狱”,在这种情况下,您在另一个和另一个内部有一个嵌套函数等等......

我希望这可以为您提供一些信息,并让您回到正确的轨道上。在您投入大量的 Node.js 工作(或者,就此而言,任何 JavaScript 繁重的网站)之前,您还应该了解一些关于 JavaScript 的其他真正有趣的东西。

【讨论】:

    【解决方案2】:

    感谢您的回答。我想我或多或少地理解了这个问题。我决定使用您的最后一个解决方案,但在与代码斗争了三个小时后,我终于决定再次编写。

    如何将 id 变量传递给 api resquests 回调函数,因为它只有三个固定参数?

    我的意思是我不能这样做:

    request(url, function(err, resp, body, id) {//using here the returned body and the id too..}
    

    我不知道如何解决这个问题,因为它不允许我添加另一个参数,我得到错误...

    问候,

    【讨论】:

      猜你喜欢
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-11
      • 2014-12-29
      相关资源
      最近更新 更多