问题
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