node.js&express – 应用程序结构的全局模块和最佳实践

我正在构build一个node.js应用程序,它是一个REST api,使用express和mongoose作为我的mongodb。 我已经得到了所有的CRUD端点,但是我只是想知道两件事情。

  1. 如何在这种路由上进行扩展,特别是如何在路由之间共享模块。 我希望我的每一个路线都进入一个新的文件,但显然只有一个数据库连接,你可以看到我已经在people.js的顶部包括mongoose。

  2. 我必须在我的people.js中写出三次模型的模式吗? 第一个模式定义模型,然后列出createPerson和updatePerson函数中的所有variables。 这感觉就像我在一天后做了php / mysql CRUD。 对于更新function,我试过编写一个循环来通过“p”循环来自动检测要更新的字段,但无济于事。 任何提示或build议将是伟大的。

另外,我会对整个应用程序有任何意见,对节点来说是新的,很难知道你做事的方式是最有效的或“最佳”的做法。 谢谢!

app.js

// Node Modules var express = require('express'); app = express(); app.port = 3000; // Routes var people = require('./routes/people'); /* var locations = require('./routes/locations'); var menus = require('./routes/menus'); var products = require('./routes/products'); */ // Node Configure app.configure(function(){ app.use(express.bodyParser()); app.use(app.router); }); // Start the server on port 3000 app.listen(app.port); /********* ENDPOINTS *********/ // People app.get('/people', people.allPeople); // Return all people app.post('/people', people.createPerson); // Create A Person app.get('/people/:id', people.personById); // Return person by id app.put('/people/:id', people.updatePerson); // Update a person by id app.delete('/people/:id', people.deletePerson); // Delete a person by id console.log('Server started on port ' + app.port); 

people.js

 //Database var mongoose = require("mongoose"); mongoose.connect('mongodb://Shans-MacBook-Pro.local/lantern/'); // Schema var Schema = mongoose.Schema; var Person = new Schema({ first_name: String, last_name: String, address: { unit: Number, address: String, zipcode: String, city: String, region: String, country: String }, image: String, job_title: String, created_at: { type: Date, default: Date.now }, active_until: { type: Date, default: null }, hourly_wage: Number, store_id: Number, // Inheirit store info employee_number: Number }); var PersonModel = mongoose.model('Person', Person); // Return all people exports.allPeople = function(req, res){ return PersonModel.find(function (err, person) { if (!err) { return res.send(person); } else { return res.send(err); } }); } // Create A Person exports.createPerson = function(req, res){ var person = new PersonModel({ first_name: req.body.first_name, last_name: req.body.last_name, address: { unit: req.body.address.unit, address: req.body.address.address, zipcode: req.body.address.zipcode, city: req.body.address.city, region: req.body.address.region, country: req.body.address.country }, image: req.body.image, job_title: req.body.job_title, hourly_wage: req.body.hourly_wage, store_id: req.body.location, employee_number: req.body.employee_number }); person.save(function (err) { if (!err) { return res.send(person); } else { console.log(err); return res.send(404, { error: "Person was not created." }); } }); return res.send(person); } // Return person by id exports.personById = function (req, res){ return PersonModel.findById(req.params.id, function (err, person) { if (!err) { return res.send(person); } else { console.log(err); return res.send(404, { error: "That person doesn't exist." }); } }); } // Delete a person by id exports.deletePerson = function (req, res){ return PersonModel.findById(req.params.id, function (err, person) { return person.remove(function (err) { if (!err) { return res.send(person.id + " deleted"); } else { console.log(err); return res.send(404, { error: "Person was not deleted." }); } }); }); } // Update a person by id exports.updatePerson = function(req, res){ return PersonModel.findById(req.params.id, function(err, p){ if(!p){ return res.send(err) } else { p.first_name = req.body.first_name; p.last_name = req.body.last_name; p.address.unit = req.body.address.unit; p.address.address = req.body.address.address; p.address.zipcode = req.body.address.zipcode; p.address.city = req.body.address.city; p.address.region = req.body.address.region; p.address.country = req.body.address.country; p.image = req.body.image; p.job_title = req.body.job_title; p.hourly_wage = req.body.hourly_wage; p.store_id = req.body.location; p.employee_number = req.body.employee_number; p.save(function(err){ if(!err){ return res.send(p); } else { console.log(err); return res.send(404, { error: "Person was not updated." }); } }); } }); } 

我在这里采取了另一种方法。 不是说这是最好的,但让我解释一下。

  1. 每个模式(和模型)都在它自己的文件(模块)
  2. 特定REST资源的每组path都在它们自己的文件(模块)中
  3. 每个路由模块只require它所需要的Mongoose模型(只有1个)
  4. 主文件(应用程序入口点)只require所有的路由模块来注册它们。
  5. Mongo连接位于根文件中,并作为parameter passing给它。

我有我的应用程序根下的两个子文件夹 – routesschemas

这种方法的好处是:

  • 你只写一次模式。
  • 你不会污染你的主要应用程序文件,每个REST资源的路由注册4-5个路由(CRUD)
  • 您只能定义一次数据库连接

以下是特定模式文件的外观:

文件:/schemas/theaterSchema.js

 module.exports = function(db) { return db.model('Theater', TheaterSchema()); } function TheaterSchema () { var Schema = require('mongoose').Schema; return new Schema({ title: { type: String, required: true }, description: { type: String, required: true }, address: { type: String, required: true }, latitude: { type: Number, required: false }, longitude: { type: Number, required: false }, phone: { type: String, required: false } }); } 

以下是特定资源的路由集合:

文件:/routes/theaters.js

 module.exports = function (app, options) { var mongoose = options.mongoose; var Schema = options.mongoose.Schema; var db = options.db; var TheaterModel = require('../schemas/theaterSchema')(db); app.get('/api/theaters', function (req, res) { var qSkip = req.query.skip; var qTake = req.query.take; var qSort = req.query.sort; var qFilter = req.query.filter; return TheaterModel.find().sort(qSort).skip(qSkip).limit(qTake) .exec(function (err, theaters) { // more code }); }); app.post('/api/theaters', function (req, res) { var theater; theater.save(function (err) { // more code }); return res.send(theater); }); app.get('/api/theaters/:id', function (req, res) { return TheaterModel.findById(req.params.id, function (err, theater) { // more code }); }); app.put('/api/theaters/:id', function (req, res) { return TheaterModel.findById(req.params.id, function (err, theater) { // more code }); }); app.delete('/api/theaters/:id', function (req, res) { return TheaterModel.findById(req.params.id, function (err, theater) { return theater.remove(function (err) { // more code }); }); }); }; 

这里是根应用程序文件,初始化连接并注册所有路由:

文件:app.js

 var application_root = __dirname, express = require('express'), path = require('path'), mongoose = require('mongoose'), http = require('http'); var app = express(); var dbProduction = mongoose.createConnection('mongodb://here_insert_the_mongo_connection_string'); app.configure(function () { app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); app.use(express.static(path.join(application_root, "public"))); app.use('/images/tmb', express.static(path.join(application_root, "images/tmb"))); app.use('/images/plays', express.static(path.join(application_root, "images/plays"))); app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); }); app.get('/api', function (req, res) { res.send('API is running'); }); var theatersApi = require('./routes/theaters')(app, { 'mongoose': mongoose, 'db': dbProduction }); // more code app.listen(4242); 

希望这是有帮助的。

我发现这个StackOverflow发布非常有帮助:

Mongoose&NodeJS项目的文件结构

诀窍是将您的架构放入models目录。 那么,在任何路线上,你都可以require('../models').whatever

另外,我通常在app.js中启动mongoose db连接,并且只有在连接启动后才启动Express服务器:

 mongoose.connect('mongodb://localhost/whateverdb') mongoose.connection.on('error', function(err) { console.log("Error while connecting to MongoDB: " + err); process.exit(); }); mongoose.connection.on('connected', function(err) { console.log('mongoose is now connected'); // start app here http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); }); }); 

我会看看这个项目https://github.com/madhums/node-express-mongoose-demo 。 这是如何以标准方式构buildnodejs应用程序的一个很好的例子。