Node.js - 在查詢中查詢,然后使用Express呈現結果

[英]Node.js - Query within a query, then render results using Express


I'm new to Node from the lands of C#, PHP and Python. I've been working days in many variations of the same problem - how can I retrieve a set of data, based on that data, retrieve another set, then render the results out. I've tried the method below, event based (client.on("row")) and the async module and I can't get any to produce the right results. In the end, I'd like to pass a projects object with tasks added to Express to render.

我是C#,PHP和Python領域的新手Node。我已經在同一個問題的許多變體中工作了幾天 - 如何根據該數據檢索一組數據,檢索另一組,然后渲染結果。我已經嘗試了下面的方法,基於事件(client.on(“row”))和異步模塊,我無法得到任何產生正確的結果。最后,我想傳遞一個項目對象,其中任務添加到Express以進行渲染。

Could anyone help me out of this hole?

任何人都可以幫助我走出這個洞嗎?

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

};

UPDATE: Meryn below provides a good solution to my issue, just to share that information, in the end, below his code with a little touch up to get it to operate: (thanks Meryn!)

更新:下面的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 个解决方案

#1


1  

You need to familiarize yourself with asynchronous flow-control. It can be tricky because the async functions (postgres queries in this case) will execute right after another in the same turn of the event loop, while the results come trickling in in subsequent turns.

您需要熟悉異步流控制。這可能很棘手,因為異步函數(在這種情況下為postgres查詢)將在事件循環的同一回合中一個接一個地執行,而結果在后續轉彎中逐漸流入。

For your code example, this effectively means that i will be set to projects.rowCount-1 and project will be set to projects.rows[project.rowCount-1] almost instantly, while the queries have been queued up. They stay like this after the result for the queries come in. Not what you want.

對於你的代碼示例,這實際上意味着我將被設置為projects.rowCount-1並且項目將幾乎立即設置為projects.rows [project.rowCount-1],而查詢已經排隊。在查詢結果出來之后,它們會保持這樣。不是你想要的。

The quickes solution is to use the Async library. https://github.com/caolan/async . This will handle the tedious bean-counting for you.

quickes解決方案是使用Async庫。 https://github.com/caolan/async。這將為您處理繁瑣的豆子計數。

For this particular example, you'd replace the code within the client.connect callback with something like

對於此特定示例,您將使用類似的內容替換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});
    })
  }

Note that because how Javascript object references work, the objects part of the project.rows array will be actually modified in place. This wouldn't be the case if you'd actually try to assign a new value to the projectRow variable.

請注意,由於Javascript對象引用的工作方式,project.rows數組的對象部分將實際修改到位。如果您實際嘗試為projectRow變量分配新值,則情況並非如此。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2013/05/09/335c4534e5d53cc56cae15e96b4f5587.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com