MissingSchemaError: Schema hasn't been registered for model "User"

In my models/user.js file:

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

var userSchema = new Schema({
    (define schema)
});
...
(save user)
...
(check password)
...
mongoose.model('User', userSchema);

And in my router/index.js, I have:

var mongoose = require('mongoose');
var User = mongoose.model('User');

which throws the error:

MissingSchemaError: Schema hasn't been registered for model "User".

If however, in user.js, I do (in the last line)

module.exports = mongoose.model('User', userSchema);

and in index.js I do var User = require('../models/User');, then everything works.

But it should not, because in config/pass.js I am doing var User = mongoose.model('User'); and it's working flawlessly.

The require('../models/User'); syntax isn't working on Ubuntu, but is on my Mac.

What should I do? How do I fix it? I have looked at tons of sample apps, including MEAN but nothing was really helpful.


Solution 1:

I got the same problem when I am trying the MEAN tutorial.

After done a little bit research, I found that in app.js, if I put require("./models/User") before var routes = require("./routes/index"), then it works.

Like this:


mongoose.connect("mongodb://localhost/news");
require("./models/Posts");
require("./models/Comments");

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

Hope the answer will be helpful!

Solution 2:

The error occurs because the models/user.js has not been interpreted by the time router/index.js has been loaded. One way to solve this would be to do the following:

var mongoose = require('mongoose');
//Load all your models
var User = require('./../models/user.js');

//Now, this call won't fail because User has been added as a schema.
mongoose.model('User');

This, however, turns out to be against best practises, which dictates that all this config stuff should happen at the start of your app.js file. Look at this example from madhums' example project

var models_path = __dirname + '/app/models'
fs.readdirSync(models_path).forEach(function (file) {
  if (~file.indexOf('.js')) require(models_path + '/' + file)
})

Note that he is loading his models before setting the app's router. As for the Ubuntu vs Mac issue, I believe it is because a relative path in Ubuntu has to start with ./. You just have to change it to ./../models/user.js, which works on Mac.

Solution 3:

All code in your mongoose schema js files should have run before it is used in other files.

For example, the following code snippet makes sure the mongoose schema files/modules are executed.

fs.readdirSync(__dirname + '/app/models').forEach(function (file) { if (~file.indexOf('.js')) require(__dirname + '/app/models/' + file); });

or schema files can be manually executed by calling

var User = require('./app/models/user.js')

before the models are used anywhere in the application.

Once the above is done, other modules that uses mongoose models can be required/executed.

Solution 4:

I literally research lot and I found a solution so, I share this solution to you so, no one can face that cheap mistake that I did.

Please remember, you just need to add the same name in ref as you gave in your model because its case sensitive ( Product !== product ).

const Product = new mongoose.model('Product', productSchema);

product: {
    type: mongoose.Schema.ObjectId,
    ref: 'Product', <-- Should be same as modelName
    required: [true, 'Cart must belong to a product']
}

Solution 5:

This problem occurred when try to get model before load the model file load

I solved same problem in my mean.io project

In controller:

'use strict';
require('../models/settingsModel'); // load settingsModel.js file before get mongoose.model('Settings')
var mongoose = require('mongoose'),
    Settings = mongoose.model('Settings'),
    Q = require('q');