我使用Nodejs,MongoDB和Express进行编码。下面的代码在MongoDB中查找具有特定id的用户对象。找到用户对象后,它将检索该对象的收藏夹属性。最喜欢的属性是一个数组,其每个元素都是产品的_id。我试图循环遍历这个数组。对于每个循环,我尝试从MongoDB检索产品对象并将此产品对象附加到新数组(在我的代码下面称为“list”)。我放了一些console.log()来检查列表的值。它对每个循环都有价值,但最后当我得到最后一个循环时,它有空。我知道问题发生是因为我没有正确使用deferred.resolve和deferred.promise。请帮助我解释deferred.resolve和deferred.promise在代码中的工作原理。非常感谢你
function showBasket(user) {
var deferred = Q.defer();
var list =[];
db.users.findById(user, function (err, user) {
if (err) deferred.reject(err);
if (user) {
var favorite = user.favorite;
favorite.forEach(function(e){
db.products.findById(mongo.helper.toObjectID(e), function(err, product){
if (err) deferred.reject(err);
if (product) {
list.push(product);
console.log(list);// list has value here
}
})//end db.products.findById
})//end of forEach
} //end of if
console.log(list);// But finally, list has null value here
deferred.resolve(list);
});//end of db.users.findById
return deferred.promise;
}
答案 0 :(得分:1)
这是一个异步问题,但是您的forEach
没用,因为有$in
运算符可以获取字段值等于数组中任何值的所有文档:
db.products.find({
"_id": {
"$in": user.favorite
}
}, function(err, products) {
// here products is an array of product
if (err) {
console.log(err);
deferred.reject(err);
} else {
console.log(products);
deferred.resolve(products);
}
})
结果是一系列匹配user.favorite
数组中所有id的产品。如果user.favorite
中的商品不属于ObjectId类型,您可能需要在查询前对每个商品执行mongo.helper.toObjectID(item)
:
var favoriteArr = [];
for (var i = 0; i < user.favorite.length;i++)[
favoriteArr.push(mongo.helper.toObjectID(user.favorite[i]));
}
// use favoriteArr with $in operator
答案 1 :(得分:1)
试试这个 由于你的foreach循环是异步的,你的输出是空的..请检查下面的答案
function showBasket(user) {
var deferred = Q.defer();
var list = [];
db.users.findById(user, function (err, user) {
if (err) deferred.reject(err);
if (user) {
var favorite = user.favorite;
// This function works like async loop (Recusrsive function)
function uploader(i) {
if (i < favorite.length) {
db.products.findById(mongo.helper.toObjectID(e), function (err, product) {
if (err) {
console.log(err);
deferred.reject(err)
};
if (product) {
list.push(product);
console.log(list);// list has value here
uploader(i + 1)
}
})//end db.products.findById
}
else {
console.log(response);
console.log(list);// This will be final result deferred.resolve(list);
}
}
uploader(0)
} //end of if
});//end of db.users.findById
return deferred.promise;
}
答案 2 :(得分:0)
下面的修改演示了在完成检索产品值的所有回调之前等待解决延迟保证的概念 - 问题是异步问题。
可能存在具有相同功能的库例程,必须有很多方法可以执行此操作,并警告此代码未经测试:
function showBasket(user) {
var deferred = Q.defer();
var list =[];
db.users.findById(user, function (err, user) {
if (err) deferred.reject(err);
if (user) {
var favorite = user.favorite;
var callbacks = favorite.length; // how many call backs are expected
if( callbacks == 0) {
deferred.resolve( list); // or reject for reason "no products"
return;
}
favorite.forEach(function(e){
db.products.findById(mongo.helper.toObjectID(e), function(err, product){
--callbacks;
if (err) {
deferred.reject(err);
}
else {
if (product) {
list.push(product);
console.log(list);// list has value here
}
if( callbacks == 0) {
console.log("all callbacks completed, resolve");
deferred.resolve(list);
}
}
})//end db.products.findById
})//end of forEach
} //end of if
});//end of db.users.findById
return deferred.promise;
}
请注意,承诺只能被解决或拒绝一次。因此,如果一个产品检索失败并且承诺被拒绝,则稍后因为所有回调都已进入而对承诺的“解决”将被忽略。