![](/img/trans.png)
[英]Mongoose use user input to find results in DB with express.js?
[英]rendering results of multiple DB/mongoose queries to a view in express.js
鉴于mongoose(或sequelize,或redis)查询的异步性质,当你在渲染视图之前需要进行多次查询时,你会怎么做?
例如,您在会话中有user_id
,并希望通过findOne
检索有关该特定用户的一些信息。 但您还希望显示最近登录用户的列表。
exports.index = function (req, res) {
var current_user = null
Player.find({last_logged_in : today()}).exec(function(err, players) {
if (err) return res.render('500');
if (req.session.user_id) {
Player.findOne({_id : req.session.user_id}).exec(function(err, player) {
if (err) return;
if (player) {
current_user = player
}
})
}
// here, current_user isn't populated until the callback fires
res.render('game/index', { title: 'Battle!',
players: players,
game_is_full: (players.length >= 6),
current_user: current_user
});
});
};
所以res.render
在第一个查询回调中,很好。 但是等待来自findOne
的响应,看看我们是否知道这个用户呢? 它只是有条件地调用,所以我不能将render
放在内部回调中,除非我为任何一个条件复制它。 不漂亮。
我可以想到一些解决方法 -
使它真的异步并在客户端使用AJAX来获取当前用户的个人资料。 但这似乎比它的价值更多的工作。
使用Q
和promises在渲染之前等待findOne
查询的解析。 但在某种程度上,这就像强制阻止使响应等待我的操作。 似乎不对。
使用中间件功能获取当前用户信息。 这看起来更干净,使查询可重用。 但是,我不确定如何去做,或者它是否仍会出现同样的问题。
当然,在一个更极端的情况下,如果你有十几个查询要做,事情可能会变得丑陋。 那么,给定这种要求的通常模式是什么?
是的,这是异步代码中特别烦人的情况。 你可以做的是把你必须复制的代码放到一个本地函数中,以保持干燥:
exports.index = function (req, res) {
var current_user = null
Player.find({last_logged_in : today()}).exec(function(err, players) {
if (err) return res.render('500');
function render() {
res.render('game/index', { title: 'Battle!',
players: players,
game_is_full: (players.length >= 6),
current_user: current_user
});
}
if (req.session.user_id) {
Player.findOne({_id : req.session.user_id}).exec(function(err, player) {
if (err) return;
if (player) {
current_user = player
}
render();
})
} else {
render();
}
});
};
但是,看看你在这里做了什么,你可能需要在多个请求处理程序中查找当前的播放器信息,所以在这种情况下你最好使用中间件。
就像是:
exports.loadUser = function (req, res, next) {
if (req.session.user_id) {
Player.findOne({_id : req.session.user_id}).exec(function(err, player) {
if (err) return;
if (player) {
req.player = player
}
next();
})
} else {
next();
}
}
然后你可以配置你的路由来调用loadUser
只要你需要req.player
填充,路由处理程序就可以直接从那里拉出玩家详细信息。
router.get("/",function(req,res){
var locals = {};
var userId = req.params.userId;
async.parallel([
//Load user Data
function(callback) {
mongoOp.User.find({},function(err,user){
if (err) return callback(err);
locals.user = user;
callback();
});
},
//Load posts Data
function(callback) {
mongoOp.Post.find({},function(err,posts){
if (err) return callback(err);
locals.posts = posts;
callback();
});
}
], function(err) { //This function gets called after the two tasks have called their "task callbacks"
if (err) return next(err); //If an error occurred, we let express handle it by calling the `next` function
//Here `locals` will be an object with `user` and `posts` keys
//Example: `locals = {user: ..., posts: [...]}`
res.render('index.ejs', {userdata: locals.user,postdata: locals.posts})
});
现在,您可以使用ExpressJS中的app.param轻松建立中间件,根据请求URL中的参数名称加载所需的数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.