我正在使用Node.js构建一个twitter克隆,使用mongoose构建MongoDB。我的Tweet
模型包含body
,user
和created
字段,其中user
是创建推文的用户的ID。现在我正在构建API。我希望当我发出GET请求以接收所有推文(/api/tweets/
)的列表但除user
字段(仅返回用户的id)之外我想获取整个用户对象这样我就可以在我的前端部分显示有关推文所有者的信息。我最终得到了以下代码。
exports.all = function (req, res, next) {
Tweet.find({}, function (err, tweets) {
if (err) return res.json(400, err);
var response = [];
tweets.forEach(function (element, index, array) {
var tweet = {};
tweet._id = element._id;
tweet.created = element.created;
tweet.body = element.body;
User.findById(element.user, function (err, user) { // <- This line
if (err) return res.json(400, err);
tweet.user = user;
});
response.push(tweet);
});
return res.json(response);
});
};
它完美无缺,但它不会添加用户信息。问题出在我标记的行中。当javascript到达那一行时,它会尝试使它成为&#34; parallel&#34;并继续执行代码而不执行回调函数。但随后它推送了尚未拥有用户信息的tweet
对象。我该如何解决这个问题?
答案 0 :(得分:2)
您将要使用async库。它会让你的生活更轻松。
// inside `Tweet.find`
async.each(tweets, function(done) {
// do stuff to tweets
User.findById(element.user, function(err, user){
if (err) return done(err);
// do stuff with user
done();
});
}, function(err) {
// called when done
res.json(response);
});
答案 1 :(得分:0)
问题在于res.json
发送了响应,因此调用findById
并不重要。一切都完成后,您需要致电res.json
。
您可以通过多种方式执行此操作,但使用现有代码最简单的方法就是保留一个计数器:
var tweetCount = 0;
tweets.forEach(/* snip */) {
User.findById(element.user, function (err, user) {
tweet.user = user;
tweetCount++;
response.push(tweet);
if (tweetCount == tweets.length) {
res.json(response);
}
});
});
答案 2 :(得分:0)
您可以将 Q 承诺库用于 同步 。它简单易用。
只有在整个承诺链完成后才会发送响应
var result = Q();
tweets.forEach(function (tweet, i) {
result = result.then(function () {
// do your stuff
}
result.then(function () {
res.json(response); //successfully completed
});