2

I'm trying to make a query that will look for a specific element in an array and print out the object that the specific element resides within. I wanna do this for every element in my dataset

Here's an example of what my dataset looks like (but with around 10k more datasets. These are just the first 2 sets in the database):

/* 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"
    ]
}

So what I want is, first of all to find the recipes where baking powder exsists, then I wanna print ot those objects where it exists. I wanna do the same for all of the ingredients. I have tried doing following to achieve this:

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


});

anyone who can explain why it's only printing out the last element in my dataset?

1
  • you have missed closure inside for loop. like this (function(i) { console.log(i); })(0) Commented Aug 10, 2018 at 12:05

4 Answers 4

2

You can try to async/await everything, so every call will be made in order, one after the other :

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)
    }
});
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. This solved my question! Not very used to asyncronous programming, gotta read up on it more. Thanks!
You're very welcome. Async programming requires some time and practice to get used to. I have optimized my code, cached the collection object, etc.
0

Don't use for loop, it isn't waiting for print output. Your for loop is not asynchronous, use async for loop.

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

Comments

0

I found out the what is an issue with it, you have missed the closure inside the for loop

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

Comments

0

Use ES6 let or closures.

Database queries in your case is asynchronous. When you are executing a query like:

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

The callback function here is executed at next tick i.e. after the completion of your whole script. So, when the current tick is finished, i (of your for loop) has become equal to allIngredients.length and that is pointing to the last element. You can mitigate this by using a closure or let (if you are using ES6) instead of var to declare your currentIngredient variable as shown below:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.