File Structure of Mongoose & NodeJS Project


Question

I currently have all my models (Schema definitions) in the /models/models.js file for my Mongoose/NodeJS application.

I'd like to break these apart into different files as such: user_account.js, profile.js, etc. However I cannot seem to do so as my controllers break and report back "cannot find module" once I pull these classes apart.

My project structure is as follows:

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

The contents of my models.js file looks like this:

var mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId;

mongoose.connect('mongodb://localhost/mydb');

var UserAccount = new Schema({
    user_name       : { type: String, required: true, lowercase: true, trim: true, index: { unique: true } }, 
    password        : { type: String, required: true },
    date_created    : { type: Date, required: true, default: Date.now }
}); 

var Product = new Schema({
    upc             : { type: String, required: true, index: { unique: true } },
    description     : { type: String, trim: true },
    size_weight     : { type: String, trim: true }
});

My user.js file (controller) looks like this:

var mongoose    = require('mongoose'), 
    UserAccount = mongoose.model('user_account', UserAccount);

exports.create = function(req, res, next) {

    var username = req.body.username; 
    var password = req.body.password;

    // Do epic sh...what?! :)
}

How can I break the schema definition into multiple files and also reference it from my controller? When I do reference it (after the schema is in a new file) I get this error:

*Error: Schema hasn't been registered for model "user_account".*

Thoughts?

1
57
2/10/2012 4:15:35 PM

Accepted Answer

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');
94
1/12/2013 8:49:23 PM

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!


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon