Node.js - 在查询中查询,然后使用Express呈现结果

时间:2013-05-09 16:59:19

标签: node.js express

我是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});
        });
      });
    });
}
};

1 个答案:

答案 0 :(得分:1)

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

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

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

对于此特定示例,您将使用类似

的内容替换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变量分配新值,则情况并非如此。