Passing reference to DB into routes is not working for my Node / Express project

六月ゝ 毕业季﹏ 提交于 2019-12-09 19:14:11

问题


I am using node + express to create a simple REST API, and am trying to separate out routing logic from db logic. I am having a problem getting access to the DB from the routes.

Here is my server.js code:

var express = require('express')
  , path = require('path')
  , http = require('http')
  , mongo = require('mongodb');

// Configure Express app
var app = express();
app.configure(function () {
    app.set('port', process.env.PORT || 3000);
    app.use(express.logger('dev'));  /* 'default', 'short', 'tiny', 'dev' */
    app.use(express.bodyParser()),
    app.use(express.static(path.join(__dirname, 'public')));
});

// Configure DB
var Server = mongo.Server
  , Db = mongo.Db
  , BSON = mongo.BSONPure
  , server = new Server('localhost', 27017, {auto_reconnect: true})
  , db = new Db('mydb', server, {safe: true});

// Open DB to see if we need to populate with data
db.open(function(err, db) {
  if(!err) {
    console.log("Connected to 'mydb' database");
    var Post = require('./routes/posts')
      , post = new Post(db);

    // Set the routes
    app.get('/:org/posts', post.find);
    app.get('/:org/posts/:id', post.get);
    app.post('/:org/posts', post.add);
    app.put('/:org/posts/:id', post.update);
    app.delete('/:org/posts/:id', post.remove);

    // Fire up the server
    http.createServer(app).listen(app.get('port'), function () {
      console.log("Express server listening on port " + app.get('port'));
    });
  }
});

and here is the logic in the post.js file:

var Post = function(db) {
  this.db = db;
};

Post.prototype.get = function(req, res) {
  var id = req.params.id;
  var org = req.params.org;
  var db = this.db;

  console.log('Retrieving post: ' + id + ' from org: ' + org);
  db.collection('ads', function(err, collection) {
    collection.findOne({'_id':new BSON.ObjectID(id), 'org':org}, function(err, item) {
      res.send(item);
    });
  });
};

Post.prototype.find = function(req, res) {
  var org = req.params.org;
  var db = this.db;

  console.log('Finding posts for org: ' + org);
  db.collection('posts', function(err, collection) {
    collection.find({'org':org}).toArray(function(err, items) {
      res.send(items);
    });
  });
};

Post.prototype.add = function(req, res) {
  var org = req.params.org;
  var post = req.body;
  var db = this.db;

  console.log('Adding post: ' + JSON.stringify(post) + ' for org: ' + org);
  db.collection('posts', function(err, collection) {
    collection.insert(post, {safe:true}, function(err, result) {
      if (err) {
        res.send({'error':'An error has occurred'});
      } else {
        console.log('Success: ' + JSON.stringify(result[0]));
        res.send(result[0]);
      }
    });
  });
};

Post.prototype.update = function(req, res) {
  var id = req.params.id;
  var org = req.params.org;
  var post = req.body;
  var db = this.db;

  delete post._id;
  console.log('Updating post: ' + id + ', org: ' + org);
  console.log(JSON.stringify(post));
  db.collection('posts', function(err, collection) {
    collection.update({'_id':new BSON.ObjectID(id)}, post, {safe:true}, function(err, result) {
      if (err) {
        console.log('Error updating post: ' + err);
        res.send({'error':'An error has occurred'});
      } else {
        console.log('' + result + ' document(s) updated');
        res.send(post);
      }
    });
  });
};

Post.prototype.remove = function(req, res) {
  var id = req.params.id;
  var org = req.params.org;
  var db = this.db;

  console.log('Deleting post: ' + id + ', org: ' + org);
  db.collection('posts', function(err, collection) {
    collection.remove({'_id':new BSON.ObjectID(id), 'org':org}, {safe:true}, function(err, result) {
      if (err) {
        res.send({'error':'An error has occurred - ' + err});
      } else {
        console.log('' + result + ' document(s) deleted');
        res.send(req.body);
      }
    });
  });
};

module.exports = Post;

I would think that the post object would hold on to the db reference for use when it is called from the routes, but I get the following error:

TypeError: Cannot call method 'collection' of undefined
    at Post.find (../routes/posts.js:23:6)

Can anyone point me in the right direction? Many thanks


回答1:


Your post object is lost as the this in your Post methods when called by the Express route handlers you're registering. You need to bind the methods to your post instance so that no matter how they're called by Express, this will be your post. Like this:

// Set the routes
app.get('/:org/posts', post.find.bind(post));
app.get('/:org/posts/:id', post.get.bind(post));
app.post('/:org/posts', post.add.bind(post));
app.put('/:org/posts/:id', post.update.bind(post));
app.delete('/:org/posts/:id', post.remove.bind(post));



回答2:


Try this way. It became my favourite way of writing modules since I found this on Stack Overflow some time ago.

server.js:

...    
var Post = require('./routes/posts')(db);
...

posts.js:

...
module.exports =function(db) {
        var module = {};

         module.get = function(req, res){
            ...
            /* db should be accessible here */

         }

         return module;
}


来源:https://stackoverflow.com/questions/14149270/passing-reference-to-db-into-routes-is-not-working-for-my-node-express-project

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!