I have models in mongoose defined as follows:
user.js
module.exports = function() {
var mongoose = require('mongoose');
// Creates a new Mongoose Schema object
var Schema = mongoose.Schema;
// Collection to hold users
var UserSchema = new Schema({
username: { type: String, required: true },
password: { type: String, required: true },
},{
versionKey: false
}
);
// Creates the Model for the User Schema
var User = mongoose.model('User', UserSchema);
var getUserById = function(id, callback) {
User.findById(id, callback);
}
var getUserByUsername = function(username, callback) {
var query = {username: username};
User.findOne(query, callback);
}
return {
getUserById: getUserById,
getUserByUsername: getUserByUsername
}
}()
Basically I am returning a public interface that clients of the User model can use. I.E. my routes for users grabs the model and can call the two public methods defined and nothing else. I am doing this to abstract the fact the I am using mongodb/mongoose from my routes. I will very likely have a User model that talks to postgres as well at some point, or may just switch to postgres. As such I don't want to have to look through the code for places in routes methods that called mongoose specific functions.
Here is my problem. Most everywhere in the code when I need a module I call
var someUtil = require('./someUtil');
However if I do that more than once for a mongoose model I get an error stating that it cannot be defined twice.
var User = require('./user'); // Cannot put this in more than one file without getting an error.
Is there a better way to code the user.js file such that I can provide a public interface to my User model but only define the Schema once so that I can call require more than one time on that file?
You should separate the Mongoose model from the service you wrap it with.
I'd suggest you have a models folder, with 1 file per schema, each file will look a bit like this:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema
var User = new Schema({
...fields your schema will have
})
//additional virtuals or configuration
module.exports = mongoose.model('User', User)
then have a services folder with a UserService that requires that model:
var User = require('../models/User')
function UserService(){
//create User, delete User, etc.
}
module.exports = new UserService()
then from now on in your controllers or routes just require the UserService. You won't have this kind of problems and your code is better organized.
I have run into this issue as well.
Something you can do is wrap the schema definition in a try catch
Replace this line var User = mongoose.model('User', UserSchema); with:
var User;
try {
User = mongoose.model('User', UserSchema);
}
catch(e) {
User = mongoose.model('User');
}
Not sure if its the best way but it will work.
Andreas is correct:
AFAIK node caches the result of requireing a module, and thus the above function should not be run twice. Other than that there's no reason to wrap you code in a self-executing function, just expose the methods like exports.getUserById = getUserById; //etc.
I've run into this problem and I thought I would contribute my answer. The issue I have is slightly more complicated because I have 'ref' definitions in my schemas. I haven't quite got to the bottom of the "why" but basically what's happening is somehow the dependency chain is causing node to require the same file twice. This is verified, as I get the console.log output twice. My prior approach had been to simply export the schemas instead of the models, but this got annoying because I had to bootstrap all the models at the start of execution. After some tinkering, I settled on this paradigm (using coffeescript):
Mongoose = require 'mongoose'
unless 'Foo' in Mongoose.modelNames()
schema = new Mongoose.Schema
bar: String
Mongoose.model 'Foo', schema
module.exports = Mongoose.model 'Foo'