File Structure of Mongoose & NodeJS Project

Here's a sample app/models/item.js

var mongoose = require("mongoose");

var ItemSchema = new mongoose.Schema({
  name: {
    type: String,
    index: true
  },
  equipped: Boolean,
  owner_id: {
    type: mongoose.Schema.Types.ObjectId,
    index: true
  },
  room_id: {
    type: mongoose.Schema.Types.ObjectId,
    index: true
  }
});

var Item = mongoose.model('Item', ItemSchema);

module.exports = {
  Item: Item
}

To load this from an item controller in app/controllers/items.js I would do

  var Item = require("../models/item").Item;
  //Now you can do Item.find, Item.update, etc

In other words, define both the schema and the model in your model module and then export just the model. Load your model modules into your controller modules using relative require paths.

To make the connection, handle that early in your server startup code (server.js or whatever). Usually you'll want to read the connection parameters either from a configuration file or from environment variables and default to development mode localhost if no configuration is provided.

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost');

A couple answers here really helped me develop an alternative approach. The original question is regarding breaking just the Schema definition out, but I prefer to bundle the Schema and Model definitions in the same file.

This is mostly Peter's idea, only exporting the model definition by overriding module.exports to make accessing the model from your controller a little less verbose:

Project layout:

MyProject
  /controllers
    user.js
    foo.js
    bar.js
    // ... etc, etc
  /models
    Item.js
  server.js

models/Item.js would look like:

var mongoose = require("mongoose");

var ItemSchema = new mongoose.Schema({
  name: {
    type: String,
    index: true
  }
});

module.exports = mongoose.model('Item', ItemSchema); 
// Now `require('Item.js')` will return a mongoose Model,
// without needing to do require('Item.js').Item

And you access the model in a controller, say user.js, like:

var Item = require(__dirname+'/../models/Item')

...

var item = new Item({name:'Foobar'});

Don't forget to call mongoose.connect(..) in server.js, or wherever else you deem appropriate!


I recently answered a Quora question with regard to this same problem. http://qr.ae/RoCld1

What I have found very nice and saves on the amount of require calls is to structure your models into a single directory. Make sure you only have a single model per file.

Create an index.js file in the same directory as your models. Add this code to it. Be sure to add the necessary fs require

var fs = require('fs');

/*
 * initializes all models and sources them as .model-name
 */
fs.readdirSync(__dirname).forEach(function(file) {
  if (file !== 'index.js') {
    var moduleName = file.split('.')[0];
    exports[moduleName] = require('./' + moduleName);
  }
});

Now you can call all your models as follows:

var models = require('./path/to/models');
var User = models.user;
var OtherModel = models['other-model'];

Peter Lyons pretty much covered the basis.
Borrowing from the above example (removing the lines after the schema) I just wanted to add:

app/models/item.js

note: notice where `module.exports` is placed
var mongoose = require("mongoose");

var ItemSchema = module.exports = new mongoose.Schema({
  name: {
    type: String,
    index: true
  },
  ...

});

To load it from the app/controllers/items.js

var mongoose = require('mongoose');
var Item = mongoose.model('Item', require('../models/item'));  

Another way without the module.exports or require:

app/models/item.js

var mongoose = require("mongoose");

var ItemSchema = new mongoose.Schema({
  name: {
    type: String,
    index: true
  },
  ... 

});

mongoose.model('Item', ItemSchema); // register model

In the app/controllers/items.js

var mongoose = require('mongoose')
  , Item = mongoose.model('Item');  // registered model

Inspired by sequelize-cli, I have a models directory where i define all schema.

Complete app on github: https://github.com/varunon9/node-starter-app-mongo

models/index.js-

'use strict';

const fs        = require('fs');
const path      = require('path');
const mongoose = require('mongoose');//.set('debug', true);
const basename  = path.basename(__filename);
const env       = process.env.NODE_ENV || 'development';
const config    = require(__dirname + '/../config/config.json')[env];
const db        = {};

const Schema = mongoose.Schema;

fs
    .readdirSync(__dirname)
    .filter(fileName => {
        return (
            fileName.indexOf('.') !== 0) 
                    && (fileName !== basename) 
                    && (fileName.slice(-3) === '.js'
        );
    })
    .forEach(fileName => {
        const model = require(path.join(__dirname, fileName));
        const modelSchema = new Schema(model.schema);

        modelSchema.methods = model.methods;
        modelSchema.statics = model.statics;

        // user.js will be user now
        fileName = fileName.split('.')[0];
        db[fileName] = mongoose.model(fileName, modelSchema);
    });

module.exports = db;

models/user.js-

'use strict';

module.exports = {
    schema: {
        email: {
            type: String,
            required: true,
            unique: true,
        },
        mobile: {
            type: String,
            required: false
        },
        name: {
            type: String,
            required: false
        },
        gender: {
            type: String,
            required: false,
            default: 'male'
        },
        password: {
            type: String,
            required: true
        },
        dob: {
            type: Date,
            required: false
        },
        deactivated: {
            type: Boolean,
            required: false,
            default: false
        },
        type: {
            type: String,
            required: false
        }
    },

    // instance methods goes here
    methods: {

    },

    // statics methods goes here
    statics: {
    }
};