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
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。