R-R
R-R

Reputation: 347

Express js,mongodb: "ReferenceError: db is not defined" when db is mentioned outside post function

The index.js file:

var express = require('express');
var router = express.Router();

function validCheck (exp,name) {
    return exp.test(name);
}
/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index');
});

var user=db.collection('user'); //gives reference error,db is not defined

router.post('/',function(req,res,next){
    username=req.body.username;
    password=req.body.password;
    //var user=db.collection('user'); //works fine
    user.findOne({'username':username,'password':password},function(err,docs){
        //do something
    });
});

module.exports = router;

When using var user=db.collection('user') outside router.post, it gives the error but when the same is used inside router.post, it works fine.

what might be the concept I am missing here?

Edit: part of App.js file involving mongodb

var mongodb= require('mongodb');
var MongoClient= mongodb.MongoClient;
var URL = 'mongodb://127.0.0.1:27017/mainDB';

MongoClient.connect(URL,function(err,database){
  if(!err){
    db=database;
  }
  else{
    //do something
  }
});

Upvotes: 1

Views: 60030

Answers (4)

Mohit Sharma
Mohit Sharma

Reputation: 687

var mongo = require('mongodb');
var url = "mongodb://localhost:27017/qanda";
mongo.MongoClient.connect(url, function(err, db) {
    if (err) throw err;
    console.log("Database created!");
    db.close();
});

Upvotes: 0

Anand S
Anand S

Reputation: 1138

MongoClient.connect's callback function is called asynchronously only after it is connected to the database. At the time only you are defining db as a global variable.

Assuming you require index.js file in app.js. The line var user=db.collection('user'); outside router.post is executed synchronously. By the time this line is executed db would have not be defined.

The line var user=db.collection('user'); inside router.post is executed asynchronously. So, when that code is executed db is already defined.

To your question:

what might be the concept I am missing here?

I suggest you to learn about asynchronous javascript execution https://stackoverflow.com/a/7104633/3492210

Upvotes: 0

Arnold Daniels
Arnold Daniels

Reputation: 16583

Remember MongoClient.connect() is async. The database connection might not be ready at the time you do var user=db.collection('user');. The database connection has been made one the callback is done, no earlier than that.

When the first request is done, the database connection just happens to be established. The longer you wait the more likely it is that is works, but still it's the wrong approach.

Also working with global variables is bad practice and leads to confusion and other problems.

In short the code should look like

// module database.js
var mongodb= require('mongodb');
var MongoClient= mongodb.MongoClient;
var URL = 'mongodb://127.0.0.1:27017/mainDB';

var db;
var error;
var waiting = []; // Callbacks waiting for the connection to be made

MongoClient.connect(URL,function(err,database){
  error = err;
  db = database;

  waiting.forEach(function(callback) {
    callback(err, database);
  });
});

module.exports = function(callback) {
  if (db || error) {
    callback(error, db);
  } else {
    waiting.push(callback);
  }
}
}

Than use it like

var db = require('database.js');

router.post('/',function(req,res,next){
  username=req.body.username;
  password=req.body.password;

  db.conn(function(err, database) {
    if (err) {
      res.sendStatus(500);
      console.log(err);
      return;
    }

    database.collection('users').findOne({'username':username, 'password':password}, function(err, docs){
      //do something
    });
  });
});

Note that the connection is made on the first require, so if you add require('database.js'); in App.js. You don't loose the on the first request.

Alternatively you can use promises, which takes care of the waiting logic for you.

Upvotes: 1

Joost Vunderink
Joost Vunderink

Reputation: 1236

What you are missing is the timing of execution.

The var user line outside router.post is executed immediately when index.js is processed by node.js.

The var user line inside router.post is only executed when a client requests the / page of your app.

The db variable is only assigned after the connection to your MongoDB has been made successfully. This is too late for the first var user line, but in time for the first HTTP request to /.

Upvotes: 0

Related Questions