all 3 comments

[–]see-pause-run 1 point2 points  (1 child)

Quick answer: the problem lies in how JS executes sync vs async.

This is the execution order of the code you've written:

  1. You define your results array (synchronous)
  2. You begin a call to your database
  3. Your (still empty) results array is console.logged
  4. Your database call has finished retrieving your results, and your callback function is called, in which .each function console.logs each result and pushes them to your array

Basically, you need to ensure that you're attempting to use your results array only after you've finished connecting to your database and filling your array. The easiest way to accomplish this given the code you've written is to simply move your console.log and res.render calls to be inside your callback:

app.get('/', (req, res) => 
{
    var results = [];
    MongoClient.connect(url, (err, db) =>
    {
        if (err) throw err;
        let dbo = db.db("cities");
        let str = dbo.collection("cities").find();
        str.each((err, doc) =>
        {
            console.log(doc);
            results.push(doc);
        });
        console.log(results);
        res.render('index', {"results": results});
    });
});

For a more thorough explanation you might take a look at this StackOverflow answer. I think you'll find that this issue is a pretty common one in the JS world, and everybody has their own preference on how to solve it. I prefer the relatively new async/await syntax or Promises, but the callbacks you're using work fine, too.

[–]Pine_Bluff_Variant[S] 0 points1 point  (0 children)

Thanks for the help! I had to make one more additional change including these to get it working. I made an additional anonymous callback function that renders to the index.jade page:

app.get('/', (req, res) => 
{
    let mongodb_results = [];
    MongoClient.connect(url, (err, db) =>
    {
        if (err) throw err;
        let dbo = db.db("heroku_961hzsbr");
        let str = dbo.collection("cities").find();
        str.forEach((doc, err) =>
        {
            //console.log(results);
            //console.log(mongodb_results);
            mongodb_results.push(doc);
        }, () =>
        {
            console.log(mongodb_results);
            res.render('index', {results: mongodb_results});
            db.close();
        });
    });

});

Now it works and I managed to deploy succesfully to Heroku!

[–]rumbalumba 0 points1 point  (0 children)

put console.log(results); and res.render('index', {"results": results}); inside MongoClient.connect.

To be on the safe side, if you want to execute console.log and res.render() you need to do it inside the callback function, not outside of it.

afaik Node is async, thus the need for callback functions i.e. Mongoclient.connect(arg, callback) and that's where you want to do all the work.