0

I am trying to create a Jeopardy like game. I have the topics for the game in a database. When the page is opened I want it to get 6 topics randomly from the database. I am putting them in an array which I will then pass to my ejs file. The problem is that when I go to pass the array to the ejs file, it is always empty. I understand that it is because of promises(actually queries) from Mongoose. My problem is that I cannot figure out how to handle this. I have read the Mongoose docs and searched everywhere but I can't figure it out.

I have tried using callbacks, but they usually just make the program hang and do nothing. I have tried using .then, but I must be using it wrong because it doesn't do what I want.

app.get("/", function(request, response){
    //My array to put the topics into
    var questionArr = [];
    //I need to know the number of items in db for random
    var getQuestions = Questions.countDocuments({}, function(err, count){
        for(var i = 0; i < 6; i++){
            !function(i){
                var rand = math.randomInt(count);
                //Here I get a random topic and add to array
                //Seems to work and actually get it
                Questions.findOne().skip(rand).exec(function(err, result){
                    questionArr.push(result);
                });
            }(i);
        }
    });

    //I thought this would make it wait for the function to finish so
    //that I could have my full array, but apparently not
    getQuestions.then(() => {
        //this runs before the other functions and give me a length of 0
        console.log(questionArr.length);
        response.render("jeopardy.ejs", {questions: questionArr});
    });
});

I simply need to have the render run after it gets the information from the database. However, it still just runs with an empty array. Thanks for any help, I'm pretty new to async.

Lee Morgan
  • 550
  • 1
  • 6
  • 26
  • An easier and efficient approach to get random documents in mongoose: https://stackoverflow.com/questions/39277670/how-to-find-random-record-in-mongoose – lifeisfoo Mar 25 '19 at 10:38

1 Answers1

1

I see few issues with your code:

1) You're mixing promises and callbacks which makes things more complicated. The code doesn't work mainly because you're not awaiting for Questions.findOne() results.

2) There is no Math.randomInt

In order to make it work it has to be similar to below:

Questions.countDocuments()
    .then((count) => {
        return Promise.all([...new Array(6)].map(() => {
            const rand = Math.floor(Math.random() * Math.floor(count));
            return Questions.findOne().skip(rand).exec();
        }))
    })
    .then((questionArr) => {
        response.render("jeopardy.ejs", {questions: questionArr});
    });

Best is to use async/await which will make it even more readable

app.get("/", async function(request, response){
    const count = await Questions.countDocuments();
    const questionArr = await Promise.all([...new Array(6)].map(() => {
        const rand = Math.floor(Math.random() * Math.floor(count));
        return Questions.findOne().skip(rand).exec();
    }));
    response.render("jeopardy.ejs", {questions: questionArr});
});

Also keep in mind that you better do proper error handling, but that's a subject of a separate post :)

evgeny.myasishchev
  • 4,141
  • 1
  • 20
  • 15
  • That works perfectly, thank you very much. I need some time to look over and understand it still, but thanks for the advice and help. Now that I have something that works, I can work on understanding it all. I will definitely get to the error handling, just wanted something to work first. Thanks a lot! – Lee Morgan Mar 26 '19 at 04:03
  • Hey, I read through the code and I understand it now. Thanks a lot, I have a grasp of some async stuff now. I have one question though, what is that array format with the three dots? I have never encountered that before. This here: [...new Array(6)] – Lee Morgan Mar 26 '19 at 04:28
  • hey @LeeMorgan, that's array destruction. In this case this pattern helps to do something X times. – evgeny.myasishchev Mar 26 '19 at 11:00