我最近开始使用Mongoose和Node.js,我在处理异步Mongoose查询的结果时遇到了一些困难。我有一个名为' Groups'并且一个小组可以容纳位于名为“会员”的单独集合中的成员。为了实现这一目标,每个小组都有一个名为“'成员”的字段。这是ObjectId的一个数组。此外,每个成员都有一个由ObjectId引用的配置文件。因此,每个成员都有一个名为' profile'并且配置文件存储在名为' Profiles'。
的集合中现在我想获得给定组中的配置文件列表。因此我写了这段代码:
// Function that returns a profile by a given objectId
function getprofile(profileId, profile) {
Profile
.findById(profileId)
.exec(function(err, res) {
if(err) { return null; }
if(!res) { return null; }
return res;
});
}
// Main function that returns a list of all (unique) profiles from members within a group
Group
.findById(req.params.id)
.populate('members')
.exec(function(err, group) {
if(err) { return handleError(res, err); }
var tmpProfiles = [];
var allProfiles = [];
for(var i=0; i<group.members.length; i++) {
var memberProfile = group.members[i].profile;
// Check if the member's profile is already in the array
if(objectIndexOf(tmpProfiles, memberProfile) == -1) {
tmpProfiles.push(memberProfile);
allProfiles.push(getprofile(memberProfile)); // add the profile to the array of profiles
}
}
return res.json(allProfiles); // this returns an empty array
});
问题在于&#39; Profile.findById&#39;功能和&#39; Group.findById&#39;函数都是异步的,因此函数返回的数组只有&#39; null&#39;值。我知道我可以通过使用&#39; Async&#39;来解决这个问题。图书馆,但这不是我的选择,所以我必须经历地狱回调#39;。有人可以通过解决这个问题让我朝着正确的方向前进吗?我已经找到了一些使用递归调用函数的解决方案,但我不知道如何在这种情况下实现它。
答案 0 :(得分:2)
你可以利用mongoose方法返回Promises这一事实。
注意:您需要使用Node&gt; = v0.12或在模块中使用Promise库require
。
// Function that returns a profile by a given objectId
function getprofile(profileId, profile) {
return Profile.findById(profileId); // return the Promise of this `findById` call
}
// Main function that returns a list of all (unique) profiles from members within a group
Group
.findById(req.params.id)
.populate('members')
.then(function(group) {
var tmpProfiles = [];
var promises = []; // store all promises from `getprofile` calls
for(var i = 0; i < group.members.length; i++) {
var memberProfile = group.members[i].profile;
// Check if the member's profile is already in the array
if(objectIndexOf(tmpProfiles, memberProfile) == -1) {
tmpProfiles.push(memberProfile);
promises.push(getprofile(memberProfile));
}
}
return Promise.all(promises);
})
.then(function(allProfiles) {
res.json(allProfiles);
})
.catch(function(err) {
//todo: handle error
console.log(err);
});
答案 1 :(得分:1)
我通过没有caolan/async
的回调地狱来支持你的学习!
无论如何,这是一个异步的答案,与你的OP和承诺答案进行比较
Group...exec(function(err, group){
async.waterfall([
function(done1){
var tmpUnique = [];
async.filter(group.members, function(member, done2){
var isUnique = (tmpUnique.indexOf(member.profile) === -1);
if(isUnique){ tmpUnique.push(member.profile) };
done2(isUnique);
}, function(err, uniqueMembers){
done1(err, uniqueMembers);
})
},
function(uniqueMembers, done1){
async.map(uniqueMembers, function(member, done2){
getProfile(member.profile, done2);
// rewrite getProfile(id, callback){} to callback(err, profile)
// and maybe rename the key member.profile if its an id to get the real profile?
}, function(err, uniqueProfiles){
done1(err, uniqueProfiles)
});
},
], function(err, uniqueProfiles){
//callback(err, uniqueProfiles) or do something further
})
})