52

I would like to separate my Mongoose models in a separate file. I have attempted to do so like this:

var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;

var Material = new Schema({
    name                :    {type: String, index: true},
    id                  :    ObjectId,
    materialId          :    String,
    surcharge           :    String,
    colors              :    {
        colorName       :    String,
        colorId         :    String,
        surcharge       :    Number
    }
});

var SeatCover = new Schema({
    ItemName            :    {type: String, index: true},
    ItemId              :    ObjectId,
    Pattern             :    String,
    Categories          :    {
        year            :    {type: Number, index: true},
        make            :    {type: String, index: true},
        model           :    {type: String, index: true},
        body            :    {type: String, index: true}
    },
    Description         :    String,
    Specifications      :    String,
    Price               :    String,
    Cost                :    String,
    Pattern             :    String,
    ImageUrl            :    String,
    Materials           :    [Materials]
});

mongoose.connect('mongodb://127.0.0.1:27017/sc');

var Materials = mongoose.model('Materials', Material);
var SeatCovers = mongoose.model('SeatCover', SeatCover);

exports.Materials = Materials;
exports.SeatCovers = SeatCovers;

Then, I have attempted to use the model like this:

var models = require('./models'); 

exports.populateMaterials = function(req, res){
    console.log("populateMaterials");
    for (var i = 0; i < materials.length; i++ ){
        var mat = new models.Materials();
        console.log(mat);
        mat.name = materials[i].variantName;
        mat.materialId = materials[i].itemNumberExtension;
        mat.surcharge = materials[i].priceOffset;
        for (var j = 0; j < materials[i].colors.length; j++){
            mat.colors.colorName = materials[i].colors[j].name;
            mat.colors.colorId = materials[i].colors[j].itemNumberExtension;
            mat.colors.surcharge = materials[i].colors[j].priceOffset;
        }
        mat.save(function(err){
            if(err){
                console.log(err);
            } else {
                console.log('success');
            }
        });
    }
    res.render('index', { title: 'Express' });
};

Is this a reasonable approach to referencing a model in a separate module?

rob_hicks
  • 1,734
  • 3
  • 23
  • 35

2 Answers2

77

I like to define the database outside of the models file so that it can be configured using nconf. Another advantage is that you can reuse the Mongo connection outside of the models.

module.exports = function(mongoose) {
    var Material = new Schema({
        name                :    {type: String, index: true},
        id                  :    ObjectId,
        materialId          :    String,
        surcharge           :    String,
        colors              :    {
            colorName       :    String,
            colorId         :    String,
            surcharge       :    Number
        }
    });
    // declare seat covers here too
    var models = {
      Materials : mongoose.model('Materials', Material),
      SeatCovers : mongoose.model('SeatCovers', SeatCover)
    };
    return models;
}

and then you would call it like this...

var mongoose = require('mongoose');
mongoose.connect(config['database_url']);
var models = require('./models')(mongoose);
var velvet = new models.Materials({'name':'Velvet'});
Michael Connor
  • 4,182
  • 24
  • 21
  • 17
    +1 for this approach. I personally use this myself and thought I was the only one. Good to see finally I'm doing something right from the start. – Dwayne Charrington Mar 26 '14 at 02:20
  • Don't you have to use createConnection in your model file? – alexislg Dec 30 '14 at 07:02
  • No, actually I think it's better if you don't. The models need a mongoose object and that's all they care about. Better to have the connection management in a single place and "inject" the mongoose object. This is best practice for configuration management and code reuse. – Michael Connor Dec 30 '14 at 16:08
  • You don't even have to pass mongoose to the models module to do this. Just have the models module `require('mongoose');` directly. I even define each model schema and special functionality in a separate file (module) and each exports it's own model. Also I think `mongoose.model('ModelName')` will return the model at anytime once you have defined it using `mongoose.model('ModelName', Schema)` – Gabriel Littman Feb 20 '15 at 00:40
  • 3
    @GabrielLittman I do the same and it works, but from mongoose official doc, you have to use the same instance of mongoose to define and retrieve the models –  Jun 20 '15 at 01:38
  • I'd +5 this if I could. I finally feel like I have a decent way to organize my node app models into a DAL. Thanks. – Matt West Nov 25 '17 at 03:54
8

The basic approach looks reasonable.

As an option you could consider a 'provider' module with model and controller functionality integrated. That way you could have the app.js instantiate the provider and then all controller functions can be executed by it. The app.js has to only specify the routes with the corresponding controller functionality to be implemented.

To tidy up a bit further you could also consider branching out the routes into a separate module with app.js as a glue between these modules.

almypal
  • 6,612
  • 4
  • 25
  • 25
  • 3
    https://github.com/cmarin/MongoDB-Node-Express-Blog is a good implementation of the concept outlined above. – almypal Jun 18 '12 at 08:37
  • interesting thought @aimypal. i was looking to do the same thing as rob_hicks. I'm curious though, i was looking at the code at the git link you provided, and was wondering if it would be better if we replace the PostProvider by simply adding those methods to Post.statics. i imagine it'll have the same result? – Khon Lieu Jul 19 '12 at 14:02
  • Different approaches. But have found this one to be really well organized. – almypal Jul 20 '12 at 02:42