我是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});
});
});
});
}
};
答案 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
变量分配新值,则情况并非如此。