admin管理员组

文章数量:1241127

I am having problems trying to access the "DB" database object that is created when the MongoDB client module connects to my MongoDB database.

At the moment I am getting an error stating that, within data.js, 'db' is not defined. I understand why this is - the db object is not being "passed" through to the router and then subsequently through to the controller.

What is the best way to do this?

I have tried to pass the "db" object through to the router (dataRoutes.js) but I cannot figure how to make this accessible to the controller (data.js). Could someone please help?

Please note I have not included the other routes and controllers but they simply submit a Form via the POST method to /data/submit . The controller below is meant to write this form data to the MongoDB database.

Here is the relevant code:

app.js

var express = require('express');
var path = require('path')
var MongoClient = require('mongodb').MongoClient;
var bodyParser = require('body-parser');
var app = express();

var routes = require('./routes/index');
var dataRoutes = require('./routes/dataRoutes');

app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');


MongoClient.connect("mongodb://localhost:27017/m101", function(err, db) {

    if(err) throw err;

    console.log("Successfully connected to MongoDB.");

    app.use('/', routes); // Use normal routes for wesbite
    app.use('/data', dataRoutes); 


    app.get('/favicon.ico', function(req, res) {
      res.send(204);
    });

    app.use(function(req, res, next) {
        var err = new Error('Oops Page/Resource Not Found!');
        err.status = 404;
        next(err); //Proceed to next middleware
    });

    if (app.get('env') === 'development') {
      app.use(function(err, req, res, next) {
// update the error responce, either with the error status
// or if that is falsey use error code 500
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
      });
    }

    app.use(function(err, req, res, next) {
        console.log('Error');
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: {}
        });

    });

    var server = app.listen(3000, function() {
        var port = server.address().port;
        console.log("Express server listening on port %s.", port);
    });

});

dataRoutes.js

    // router

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

    // controller references
    var ctrlsData = require('../controllers/data');

    router.post('/submit', ctrlsData.submit);


    module.exports = router;

data.js

var MongoClient = require('mongodb').MongoClient;

var sendJsonResponse = function(res, status, content) {
  res.status(status);
  res.json(content);
};

module.exports.submit = function(req, res) {
  var title = req.body.title;
  var year = req.body.year;
  var imdb = req.body.imdb;

  /*
  console.log('submitted');
  console.log(req.body);
  sendJsonResponse(res, 201, {title,year,imdb});
  */

  var title = req.body.title;
  var year = req.body.year;
  var imdb = req.body.imdb;



  if ((title == '') || (year == '') || (imdb == '')) {
    sendJsonResponse(res, 404, {
      "message": "Title, Year and IMDB Reference are all required."
    });
  } else {
      db.collection('movies').insertOne(
          { 'title': title, 'year': year, 'imdb': imdb },
          function (err, r) {
            if (err) {
              sendJsonResponse(res, 400, err);
            } else {
              sendJsonResponse(res, 201, "Document inserted with _id: " + r.insertedId + {title,year,imdb});
            }
          }
        );

  }

};

I am having problems trying to access the "DB" database object that is created when the MongoDB client module connects to my MongoDB database.

At the moment I am getting an error stating that, within data.js, 'db' is not defined. I understand why this is - the db object is not being "passed" through to the router and then subsequently through to the controller.

What is the best way to do this?

I have tried to pass the "db" object through to the router (dataRoutes.js) but I cannot figure how to make this accessible to the controller (data.js). Could someone please help?

Please note I have not included the other routes and controllers but they simply submit a Form via the POST method to /data/submit . The controller below is meant to write this form data to the MongoDB database.

Here is the relevant code:

app.js

var express = require('express');
var path = require('path')
var MongoClient = require('mongodb').MongoClient;
var bodyParser = require('body-parser');
var app = express();

var routes = require('./routes/index');
var dataRoutes = require('./routes/dataRoutes');

app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');


MongoClient.connect("mongodb://localhost:27017/m101", function(err, db) {

    if(err) throw err;

    console.log("Successfully connected to MongoDB.");

    app.use('/', routes); // Use normal routes for wesbite
    app.use('/data', dataRoutes); 


    app.get('/favicon.ico', function(req, res) {
      res.send(204);
    });

    app.use(function(req, res, next) {
        var err = new Error('Oops Page/Resource Not Found!');
        err.status = 404;
        next(err); //Proceed to next middleware
    });

    if (app.get('env') === 'development') {
      app.use(function(err, req, res, next) {
// update the error responce, either with the error status
// or if that is falsey use error code 500
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
      });
    }

    app.use(function(err, req, res, next) {
        console.log('Error');
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: {}
        });

    });

    var server = app.listen(3000, function() {
        var port = server.address().port;
        console.log("Express server listening on port %s.", port);
    });

});

dataRoutes.js

    // router

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

    // controller references
    var ctrlsData = require('../controllers/data');

    router.post('/submit', ctrlsData.submit);


    module.exports = router;

data.js

var MongoClient = require('mongodb').MongoClient;

var sendJsonResponse = function(res, status, content) {
  res.status(status);
  res.json(content);
};

module.exports.submit = function(req, res) {
  var title = req.body.title;
  var year = req.body.year;
  var imdb = req.body.imdb;

  /*
  console.log('submitted');
  console.log(req.body);
  sendJsonResponse(res, 201, {title,year,imdb});
  */

  var title = req.body.title;
  var year = req.body.year;
  var imdb = req.body.imdb;



  if ((title == '') || (year == '') || (imdb == '')) {
    sendJsonResponse(res, 404, {
      "message": "Title, Year and IMDB Reference are all required."
    });
  } else {
      db.collection('movies').insertOne(
          { 'title': title, 'year': year, 'imdb': imdb },
          function (err, r) {
            if (err) {
              sendJsonResponse(res, 400, err);
            } else {
              sendJsonResponse(res, 201, "Document inserted with _id: " + r.insertedId + {title,year,imdb});
            }
          }
        );

  }

};
Share Improve this question edited Jan 22, 2017 at 17:48 Ctrp asked Jan 22, 2017 at 17:39 CtrpCtrp 651 silver badge7 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 11

Create a db variable that reference mongodb in app.js :

MongoClient.connect("mongodb://localhost:27017/m101", function(err, db) {

    app.db = db;

    //.....
});

In data.js, access db from req.app :

module.exports.submit = function(req, res) {

    req.app.db.collection('movies').insertOne({ 'title': title, 'year': year, 'imdb': imdb },
        function(err, r) {}
    )
};

The accepted answer isn't quite correct. You shouldn't attach custom objects to the app object. That's what app.locals is for. Plus, the accepted answer will fail when using Typescript.

app.locals.db = db;

router.get('/foo', (req) => {
    req.app.locals.db.insert('bar');
});

Sure, it's longer. But you get the assurance that future updates to ExpressJS will not interfere with your object.

I understand that the answer of @Bertrand is functional, but it is not usually remended. The reason being that, from a software point of view, you should have a better separation in your software.

app.js

var express = require('express');
var path = require('path')
var MongoClient = require('mongodb').MongoClient;
var bodyParser = require('body-parser');
var app = express();

var routes = require('./routes/index');
var dataRoutes = require('./routes/dataRoutes');
var DB = require('./db.js');

app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');


DB.Init("mongodb://localhost:27017/m101")
  .then(() => {
    console.log("Successfully connected to MongoDB.");

    app.use('/', routes); // Use normal routes for wesbite
    app.use('/data', dataRoutes); 


    app.get('/favicon.ico', function(req, res) {
      res.send(204);
    });

    var server = app.listen(3000, function() {
        var port = server.address().port;
        console.log("Express server listening on port %s.", port);
    });
  })
  .catch((e) => {
    console.log("Error initializing db");
  });

db.js

var _db = null;
module.exports = {
  Init: (url) => {
    return new Promise((resolve, reject) => {
      if (!url)
        reject("You should provide a URL");
      MongoClient.connect("mongodb://localhost:27017/m101", function(err, db) {
        if(err) reject(err);
        _db = db;
        resolve(); // Or resolve(db) if you wanna return the db object
      });
    });
  },
  Submit: (req, res, next) => {
    // Whatever goes. You have access to _db here, too!
  }
};

in data.js

var DB = require('../db.js');
router.post('/submit', DB.submit);

Finally, even this answer can be improved as you are not usually advised to wait for the DB to connect, otherwise, you are losing the advantage of using ASync procs. Consider something similar to here in app.js:

Promise.resolve()
  .then(() => {
    // Whatever DB stuff are
    // DB.Init ?
  })
  .then(() => {
    // Someone needs routing?
  })
  ...
  .catch((e) => {
    console.error("Ther app failed to start");
    console.error(e);
  });

I understand that in the last sample, you can not instantly query DB as it may not have connected yet, but this is a server, and users are usually expected to wait for your DB to init. However, if you wanna more proof solution, consider implementing something yourself in DB.submit to wait for the connect. Or, you can also use something like mongoose.

本文标签: javascriptPassing Mongo DB Object DB to Express MiddlewareStack Overflow