2017-03-06 102 views
1

我使用Nodejs,MongoDB和Express编码。下面的代码在MongoDB中查找具有特定ID的用户对象。一旦找到用户对象,它将检索该对象的收藏属性。 favorite属性是一个数组,其每个元素都是产品的_id。我试图循环这个数组。在每个循环中,我尝试从MongoDB中检索一个产品对象,并将此产品对象附加到新数组(在我的代码中称为“list”)。我把一些console.log()来检查列表的值。它对每个循环都有价值,但最终当我得到最后一个循环时,它是空的。我知道问题发生,因为我没有正确使用deferred.resolve和deferred.promise。请帮我解释代码中的deferred.resolve和deferred.promise作品。非常感谢您Arrayj在Nodejs和MongoDB中使用forEach循环返回null值

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

是'db.products.findById'异步?如果是这样,'list'正在测试中,并且在'.forEach'函数中请求的任何回调之前解析延迟。回调会将产品推到“列表”上,但这是一段时间之后,在您登录列表后发现它为空。 – traktor53

+0

我不知道你使用哪个库来与MongoDB进行交互,但是如果你使用的是Mongoose(它看起来不太像),你应该看看Query Population。看看文档:http://mongoosejs.com/docs/populate.html –

+0

@SilvestreHerrera,我不使用猫鼬。我之前使用过它。这很棒。这一次,我只想尝试使用MongoDB。 – sonle

回答

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; 
} 

注意,承诺才能解决或拒绝一次。因此,如果一个产品检索失败并且承诺被拒绝,那么稍后对承诺的“解决”,因为所有的回调都已经进入而被忽略。

+0

谢谢你完美的工作! – sonle

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 
+0

@Martel,谢谢。我试过你的代码,但它发回错误400(错误的请求)。我认为db.products.find存在问题({0 {0} {0} {\“ID”{0}“:user.favorite } }我也尝试了mongo.helper.toObjectID(item)但是同样的错误 – sonle

1

尝试这个 你的输出为null becauase你的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; 
} 
+0

谢谢你,你的代码工作完美! – sonle