Mongoose-based app architecture Mongoose-based app architecture mongoose mongoose

Mongoose-based app architecture


When I first got into Node.js, Express and Mongoose I struggled with scaling my code. The intention of my answer is to help someone who's working on more than just a simple blog, but to help with an even larger scalable project.

  • I am always connected to the database, I do not open and close connections when needed
  • I use index.js as the root file of a folder, just like we'd do in other languages
  • models are kept in their own documents, and require()d into the models/index.js file.
  • routes are similar to models, each route level has a folder, which has an index.js file in turn. So it's easy to arrange something like http://example.com/api/documents/:id. It also makes more sense when one goes through the file structure.

Here's the structure of what I use:

-- app.js-- models/---- index.js---- blog.js-- mongoose/---- index.js-- routes/---- index.js---- blog/index.js-- public/-- views/---- index.{your layout engine} => I use Jade.lang-- methods/---- index.js => use if you'd rather write all your functions here---- blog.js => can store more complex logic here

app.js

var db = require('./mongoose'),  express = require('express');// note that I'm leaving out the other things like 'http' or 'path'var app = express();// get the routesrequire('./routes')(app);// I just require routes, without naming it as a var, & that I pass (app)

mongoose/index.js

// Mongoose connect is called once by the app.js & connection established// No need to include it elsewherevar mongoose = require('mongoose');mongoose.connect('mongodb://localhost/blog');// I have just connected, and I'm not exporting anything from here

models/index.js

// Logic here is to keep a good reference of what's used// modelsBlog = require('./blog');// User = require('./user');// exportsexports.blogModel = Blog.blogModel;// exports.userModel = User.userModel;

models/blog.js

So for every model that you work on you create a model.js document, and add it in the models/index.js above. As an example I've added a User model but commented it out.

// set up mongoosevar mongoose = require('mongoose');var Schema = mongoose.Schema,ObjectId = Schema.ObjectId;var BlogSchema = Schema({  header: {type: String },  author: {type: String },  text: {type: String },  _id: { type: ObjectId } // not necessary, showing use of ObjectId});Blog = mongoose.model('Blog', BlogSchema);// the above is necessary as you might have embedded schemas which you don't exportexports.blogModel = Blog;

routes/index.js

module.exports = function(app) {  app.get('/', function(req, res) {    // do stuff  });  require('./blog')(app);  // other routes entered here as require(route)(app);  // we basically pass 'app' around to each route}

routes/blog/index.js

module.exports = function(app) {  app.get('/blog', function(req, res) {    // do stuff  });  require('./nested')(app);  // this is for things like http://example.com/blog/nested  // you would follow the same logic as in 'routes/index.js' at a nested level}

suggested use

  • models: for creating the logic that deals with the documents, i.e. creating, updating, deleting, and searching.
  • routes: minimal coding, only where I need to parse http data, create instances of models, and then I send queries to the relevant model.
  • methods: for the more complex logic that doesn't directly involve models. As an example, I have an algorithms/ folder where I store all the algorithms that I use in my app.

Hope this provides more clarity. This structure is working wonders for me as I find it easy to follow.


That's pretty much how I go about it, with a few differences:

  • I don't think you can have the open listener inside your function in the db-layer. What I generally do when using a persistent connection like yours is start the application itself in the db open handler. If you don't want to use persistent connections, use createConnection in the db layer function, and make sure you close it before calling the callback. I am not sure if I am making myself clear. Let me know if you want a code example.
  • This is more of a general node.js tip, but I keep my database connection string and other configuration in a json file and require it wherever it is needed. You probably won't need another settings.js file after that.
  • You can also use schema functions (http://mongoosejs.com/docs/api.html#schema_Schema-method) to code some app functionality into your models itself.