Search code examples
node.jsmongodbpugserverside-javascriptscoping

Weird scope behavior in node or am I sleeping?


My js is as follows,

/*
 * GET home page.
 */

var MongoClient = require('mongodb'); 

exports.index = function(req, res){
    var studentObj = {};
    MongoClient.connect("mongodb://localhost:27017/MY_DB_TEST", function(err, db) {
      if(!err) {
        console.log("We are connected");        

        var collection =  db.collection('test');        
        var stream = collection.find().stream();

        stream.on("data", function(item){
            studentObj =  item;
        });     
      }
    });
    res.render('index', { title: 'Express', obj: studentObj });
};

I try to render this page with jade, my syntax for that is,

h1 Name: #{obj.name}

My JSON: (fetched from mongodb)

{
  name: "Ron",
  age: 24
}

This does not work, it only works if I keep my studentObj as a global variable i.e after the require statement.

Also, the obj.name is not rendered on first request, only for 2nd request onwards do I get the name property.

Why are these issues happening? am I missing something extremely trivial?


Solution

  • You're trying to treat async code as synchronous. Don't do that.

    Here's your code:

    // Declare local var
    var studentObj = {};
    
    // fire off an async request
    MongoClient.connect("mongodb://localhost:27017/MY_DB_TEST", function(err, db) {
    
    // render, not waiting for data to arrive from server
    res.render('index', { title: 'Express', obj: studentObj });
    

    This also explains the behaviour with global var. At first render it's still empty, but before second render the data request comes back and inits the global var. Solution is: render only after you got the data.

    stream.on("data", function(item){
      res.render('index', { title: 'Express', obj: item });
    });