【问题标题】:Array return null value with forEach loop in Nodejs and MongoDB数组在 Nodejs 和 MongoDB 中使用 forEach 循环返回空值
【发布时间】:2017-07-25 17:56:26
【问题描述】:

我正在使用 Nodejs、MongoDB 和 Express 进行编码。下面的代码在 MongoDB 中查找具有特定 id 的用户对象。一旦找到用户对象,它就会检索该对象的收藏属性。最喜欢的属性是一个数组,它的每个元素都是一个产品的_id。我试图遍历这个数组。对于每个循环,我尝试从 MongoDB 检索产品对象并将该产品对象附加到新数组(在我下面的代码中,它称为“列表”)。我放了一些 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;
}

【问题讨论】:

  • db.products.findById 是异步的吗?如果是这样,list 正在测试中,并且在 .forEach 函数中请求的任何回调之前解决了延迟。回调将产品推送到list,但这是一段时间后,您登录列表并发现它为空之后。
  • 我不知道您使用哪个库与 MongoDB 进行交互,但如果您使用的是 Mongoose(看起来不太像),您应该真正研究一下 Query Population。查看文档:mongoosejs.com/docs/populate.html
  • @SilvestreHerrera,我不使用猫鼬。我以前用过。这很棒。这一次,我只想尝试使用 MongoDB。
  • @Traktor53。谢谢你。它是异步的。我还是不太明白。你认为这是因为异步问题还是关闭问题?

标签: javascript jquery arrays node.js mongodb


【解决方案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

【讨论】:

  • @Martel,谢谢。我尝试了您的代码,但它发回错误 400(错误请求)。我认为 db.products.find({ "_id": { "$in": user.favorite } } 查询有问题。我也尝试了 mongo.helper.toObjectID(item) 但同样的错误
【解决方案2】:

下面的修改演示了等待解决延迟承诺的概念,直到所有用于检索产品值的回调都已完成 - 问题是异步问题。

可能存在具有相同功能的库例程,必须有很多方法可以做到这一点,并警告此代码未经测试:

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

请注意,promise 只能解决或拒绝一次。因此,如果一个产品检索失败并且 promise 被拒绝,则由于所有回调都已进入,因此稍后对 promise 的“解决”将被忽略。

【讨论】:

    【解决方案3】:

    试试这个 您的输出为空,因为您的 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-09
      • 1970-01-01
      • 2015-04-22
      • 2014-12-19
      • 1970-01-01
      • 2018-10-08
      • 1970-01-01
      • 2019-05-25
      • 1970-01-01
      相关资源
      最近更新 更多