【问题标题】:Mongo query inside a for-loop nodeJSfor循环nodeJS中的Mongo查询
【发布时间】:2019-01-18 00:23:34
【问题描述】:

我正在尝试进行查询,以查找数组中的特定元素并打印出特定元素所在的对象。我想对数据集中的每个元素都这样做

这是我的数据集的示例(但还有大约 10k 的数据集。这些只是数据库中的前 2 个数据集):

/* 1 */
{
    "_id" : ObjectId("5b6b19cb1be7e54a24344bd5"),
    "id" : 18009,
    "ingredients" : [ 
        "baking powder", 
        "eggs", 
        "all-purpose flour", 
        "raisins", 
        "milk", 
        "white sugar"
    ]
}

/* 2 */
{
    "_id" : ObjectId("5b6b19cb1be7e54a24344bd6"),
    "id" : 28583,
    "ingredients" : [ 
        "sugar", 
        "egg yolks", 
        "corn starch", 
        "cream of tartar", 
        "bananas", 
        "vanilla wafers", 
        "milk", 
        "vanilla extract", 
        "toasted pecans", 
        "egg whites", 
        "light rum"
    ]
}

所以我想要的是,首先找到存在发酵粉的食谱,然后我想打印那些存在的对象。我想对所有的成分做同样的事情。我已尝试执行以下操作来实现此目的:

const path = "mongodb://localhost:27017/NN_Recipes";


mongo.connect(path, function(err,db) {

    console.log("Connected!")


    var allIngredients;


    return new Promise((resolve, reject) => {
        db.collection('recipes_final').distinct("ingredients", function(err, resu) {

            allIngredients = resu;
            resolve();
        })
    }).then(data => {
        for(i = 0; i < allIngredients.length; i++) {

            var currentIngredient = allIngredients[i];

            var individualMatrix = db.collection('recipes_final').find({
                ingredients: currentIngredient
            }).toArray(function(error, response) {
                  // console.log(currentIngredient); //This will only print the very last element in the allIngredients[i], none of the other ones.

            });

            //all below is just things i tried to play around with.
        //     console.log(i)
        //     console.log(individualMatrix)
        //    console.log(allIngredients[i])
        }
       // console.log(allIngredients)
    })


});

谁能解释为什么它只打印出我数据集中的最后一个元素?

【问题讨论】:

  • 您在 for 循环中错过了 closure。像这样 (function(i) { console.log(i); })(0)

标签: javascript arrays node.js mongodb


【解决方案1】:

你可以尝试async/await一切,这样每个电话都会按顺序进行,一个接一个:

mongo.connect( path, async (err, db) => {

    const recipes = db.collection('recipes_final'),
           allIngredients = await recipes.distinct("ingredients");

    for (let ingredients of allIngredients) {
        let individualMatrix = await recipes.find({ ingredients }).toArray()
        console.log(individualMatrix)
    }
});

【讨论】:

  • 谢谢。这解决了我的问题!不太习惯异步编程,需要更多地阅读它。谢谢!
  • 不客气。异步编程需要一些时间和练习来适应。我已经优化了我的代码,缓存了集合对象等
【解决方案2】:

不要使用 for 循环,它不等待打印输出。您的 for 循环不是异步的,请使用 async for 循环。

async.each(openFiles, saveFile, function(err){
    // if any of the saves produced an error, err would equal that error
});

【讨论】:

    【解决方案3】:

    我发现它有什么问题,你错过了 for 循环内的 closure

    for(i = 0; i < allIngredients.length; i++) {
       (function(i){
            var currentIngredient = allIngredients[i];
    
            var individualMatrix = db.collection('recipes_final').find({
                ingredients: currentIngredient
            }).toArray(function(error, response) {
                  // console.log(currentIngredient); //This will only print the very last element in the allIngredients[i], none of the other ones.
    
            });
           })(i)
        }
    

    【讨论】:

      【解决方案4】:

      使用 ES6 let闭包

      您的数据库查询是异步的。当您执行如下查询时:

      db.collection('collectionName').find().toArray(callback);
      

      这里的callback 函数在下一个滴答时执行,即在整个脚本完成之后。因此,当当前刻度完成时,i(你的 for 循环)已经等于 allIngredients.length,并且指向最后一个元素。您可以通过使用 closurelet(如果您使用 ES6)而不是 var 来声明您的 currentIngredient 变量来缓解这种情况,如下所示:

      for (i = 0; i < allIngredients.length; i++) {
        let currentIngredient = allIngredients[i];
        // rest of your code
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-04
        • 2020-08-20
        • 2017-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多