0

我是来自 C#、PHP 和 Python 领域的 Node 新手。我已经在同一问题的许多变体中工作了几天-如何根据该数据检索一组数据,检索另一组数据,然后将结果呈现出来。我已经尝试了下面的方法,基于事件的 (client.on("row")) 和异步模块,但我无法得到任何产生正确的结果。最后,我想传递一个带有添加到 Express 的任务的项目对象以进行渲染。

谁能帮我走出这个洞?

exports.index = function(req, res){
req.session.user_id = 1;
if (req.session == undefined || req.session.user_id == null || req.session.user_id < 0) {
    res.redirect('/login');
} else {
    var pg = require('pg');
    var conString = "postgres://jason@localhost:5432/simpleproject";

    var client = new pg.Client(conString);

    client.connect(function(err) {
        client.query("SELECT * FROM project", function(err, projects) {



            for (var i=0; i<projects.rowCount; i++) {
                var project = projects.rows[i];

                client.query("SELECT * FROM task WHERE project_id="+projects.rows[i].id, function(err, subrows) {

                    if (subrows.rowCount > 0) {
                        project.tasks = subrows.rows;
                        console.log("adding tasks");
                    } else {
                        project.tasks = null;
                    }

                    if (i==projects.rowCount) {
                    console.log("rendering");
                    res.render('main', { title: 'My Projects', projects: projects });
                    }

                });
            }
            if (err != null) { console.log(err); }
        }
        );
    });     
}

};

更新: 下面的 Meryn 为我的问题提供了一个很好的解决方案,只是为了分享该信息,最后,在他的代码下方稍作修改以使其运行:(感谢 Meryn!)

var async = require('async');

exports.index = function(req, res){
req.session.user_id = 1;
if (req.session == undefined || req.session.user_id == null || req.session.user_id < 0) {
    res.redirect('/login');
} else {
    var pg = require('pg');
    var conString = "postgres://jason@localhost:5432/simpleproject";

    var client = new pg.Client(conString);

    var addTasksToProject = function(projectRow, cb) { // called once for each project row
    client.query("SELECT * FROM task WHERE project_id="+projectRow.id, function(err, result) {
        console.log("tasks");
      if(err) return cb(err); // let Async know there was an error. Further processing will stop
      projectRow.tasks = result.rows;
      cb(null); // no error, continue with next projectRow, if any
    });
  };

  client.connect(function(err) {
      client.query("SELECT * FROM project", function(err, projects) {
        console.log("projects");
        if (err) return console.error(err);
        async.each(projects.rows, addTasksToProject, function(err) {
          if (err) return console.error(err);
          // all project rows have been handled now
          console.log(projects.rows);
          res.render('main', { title: 'My Projects', projects: projects.rows});
        });
      });
    });
}
};
4

1 回答 1

1

您需要熟悉异步流控制。这可能很棘手,因为异步函数(在这种情况下为 postgres 查询)将在事件循环的同一轮次中紧接着执行,而结果在随后的轮次中逐渐出现。

对于您的代码示例,这实际上意味着i将设置为projects.rowCount-1并且几乎立即project设置为projects.rows[project.rowCount-1],而查询已排队。在查询结果进来后,它们保持这种状态。不是你想要的。

快速解决方案是使用 Async 库。https://github.com/caolan/async。这将为您处理繁琐的 bean 计数。

对于这个特定的示例,您可以将 client.connect 回调中的代码替换为类似

  addTasksToProject = function(projectRow, cb) { // called once for each project row
    client.query("SELECT * FROM task WHERE project_id="+projectRow.id, function(err, result) {
      if(err) return cb(err) // let Async know there was an error. Further processing will stop
      projectRow.tasks = result.rows
      cb(null) // no error, continue with next projectRow, if any
    }
  }
  client.query("SELECT * FROM project", function(err, projects) {
    if (err) return console.error(err)
    async.each(projects.rows, addTasksToProject, function(err) {
      if (err) return console.error(err)
      // all project rows have been handled now
      res.render('main', { title: 'My Projects', projects: project.rows});
    })
  }

请注意,由于 Javascript 对象引用的工作方式,数组的对象部分project.rows实际上将被修改到位。如果您实际上尝试为projectRow变量分配新值,则情况并非如此。

于 2013-05-09T19:41:22.883 回答