86
votes

I'm learning the mean stack and when I try to start the server using

npm start

I get an exception saying that:

schema hasn't been registered for model 'Post'. Use mongoose.model(name, schema)

here is my code inside /models/Posts.js

var mongoose = require('mongoose');

var PostSchema = new mongoose.Schema({
    title: String,
    link: String, 
    upvotes: { type: Number, default: 0 },
    comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});

mongoose.model('Post', PostSchema);

as I can see the schema should be registered for the model 'Post', but what can be possibly causing the exception to be thrown?

Thanks in advance.

Edit: Here's the exception error

/home/arash/Documents/projects/personal/flapper-news/node_modules/mongoose/lib/index.js:323
  throw new mongoose.Error.MissingSchemaError(name);
        ^
MissingSchemaError: Schema hasn't been registered for model "Post".
Use mongoose.model(name, schema)

and here's the app.js code with the mongoose initialization:

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/news');
require('./models/Posts');
require('./models/Comments');

before the line:

app.use('/', routes);
18
You're making a mistake somewhere else. The code above is valid. Perhaps you are "require"(ing) Post.js somewhere, but you never "exported" the model. - Neil Lunn
@NeilLunn ok I'll edit the question with my exception error, because that's all I can read from it. maybe others can see what I can't see - arash moeen
@Umm. Did you ever "export" where you "required" later? I think that is the code that is missing here. - Neil Lunn
@NeilLunn you mean in the app.js? let me put the app.js code too (mongoose part only) - arash moeen
If that id your code then you never "exported" the model. Geez Three times now. You should get this by now. - Neil Lunn

18 Answers

150
votes

It's not an issue with model export. I had the same issue.

The real issue is that require statements for the models

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/news');
require('./models/Posts');
require('./models/Comments');

were below the routes dependencies. Simply move the mongoDB dependencies above the routes dependencies. This is what it should look like:

// MongoDB
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/news');
require('./models/Posts');
require('./models/Comments');

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

var app = express();
55
votes

If someone coudn't fix it with the approach of the correct answer (like me), try to look at the creation of the schema. I wrote the 'ref' as 'User', but the correct was 'user'.

Wrong:

createdBy: {
    type: Schema.Types.ObjectId,
    ref: 'User'
}

Correct:

createdBy: {
    type: Schema.Types.ObjectId,
    ref: 'user'
}
41
votes

IF YOU USE MULTIPLE mongoDB CONNECTIONS


beware that when using .populate() you MUST provide the model as mongoose will only "find" models on the same connection. ie where:

var db1 = mongoose.createConnection('mongodb://localhost:27017/gh3639');
var db2 = mongoose.createConnection('mongodb://localhost:27017/gh3639_2');
var userSchema = mongoose.Schema({
  "name": String,
  "email": String
});

var customerSchema = mongoose.Schema({
  "name" : { type: String },
  "email" : [ String ],
  "created_by" : { type: mongoose.Schema.Types.ObjectId, ref: 'users' },
});

var User = db1.model('users', userSchema);
var Customer = db2.model('customers', customerSchema);

Correct:

Customer.findOne({}).populate('created_by', 'name email', User)

or

Customer.findOne({}).populate({ path: 'created_by', model: User })

Incorrect (produces "schema hasn't been registered for model" error):

Customer.findOne({}).populate('created_by');
18
votes

I used the following approach to solve the issue

const mongoose = require('mongoose');
const Comment = require('./comment');

const PostSchema = new mongoose.Schema({
            title: String,
            link: String, 
            upvotes: { type: Number, default: 0 },
            comments: [{ type: mongoose.Schema.Types.ObjectId, ref: Comment }]
        });
mongoose.model('Post', PostSchema);

Please look, here ref don't have string type value, now it's referring to Comment schema.

5
votes

Here's https://mongoosejs.com/docs/populate.html#cross-db-populate

It says we have to pass the model as a third argument.

For e.g.

//Require User Model
const UserModel = require('./../models/User');
//Require Post Model
const PostModel = require('./../models/Post');
const posts = await PostModel.find({})
            .select('-__v')
            .populate({
              path: 'user',
              select: 'name -_id',
              model: UserModel
            });
//or 
const posts = await PostModel.find({})
            .select('-__v')
            .populate('user','name', UserModel);
4
votes

This error also pops up when we create wrong references (ref) between mongoose models.

In my case I was referring to the file name instead of model name.

eg:

const userModel = mongoose.model("user", userSchema);

We should refer to 'user' (model name) instead of 'User' (file name);

4
votes

this problem happened when you use a model that depends on another model, but that other model didn't get registered yet.

a simple fix would be adding model to popualte instead of depending on ref in the schema

=>> example

const jobs = await Job.find({}).populate({
    path: "jobDescriptions",
    model: JobDesc,
    select: "list",
    populate: {
      path: "list",
      select:"name list",
      model: Skill,
    },
  });
2
votes
.\nodeapp\node_modules\mongoose\lib\index.js:452
      throw new mongoose.Error.MissingSchemaError(name);
      ^
MissingSchemaError: Schema hasn't been registered for model "users".
Use mongoose.model(name, schema)
    at new MissingSchemaError

I got this error resolved when use setTimeout on server.js

mongoose.connect(env.get('mongodb.uri'), { useNewUrlParser: true })
  .then(() => logger.info("MongoDB successfully connected"))
  .catch(err => logger.error(err));
app.use(passport.initialize());
setTimeout(function() {
  require("./src/utils/passport")(passport);
}, 3000);
2
votes

The issue is with the refs, always make sure to refer the refs to whatever name your are exporting from the models.

// Model

const Task = mongoose.model('**Tasks**', taskSchema);

//Refs

userSchema.virtual('tasks', {
ref: '**Tasks**',
localField: '_id', // field in current model
foreignField: 'owner' // corresponding field in other model

});

1
votes

I was also facing the same problem. The solution to my problem was looking at the ref parameter which had a different name compared to the model I was actually exporting and hence no such model was found.

userSchema.virtual('tasks', {
    ref: 'Task',
    localField: '_id',
    foreignField: 'owner'
})
  

Whereas what I had actually exported was :-

const Tasks = mongoose.model('Tasks', taskSchema)

module.exports = Tasks

After rectifying the Task as Tasks my problem was solved

0
votes

Elaborating on Rafael Grilli's answer above,

Correct:

var HouseSchema = new mongoose.Schema({
  date: {type: Date, default:Date.now},
  floorplan: String,
  name:String,
  house_id:String,
  addressLine1:String,
  addressLine2:String,
  city:String,
  postCode:String,
  _locks:[{type: Schema.Types.ObjectId, ref: 'xxx'}] //ref here refers to the first parameter passed into mongoose.model()
});
var House = mongoose.model('xxx', HouseSchema, 'houseschemas');
0
votes

You should also check that you don't have dirty data in your database. I ended up with a document containing the lowercased version of the referenced model (user instead of User). This causes the error and is incredibly hard to track down.

Easy to fix with a quick mongo query:

db.model.updateMany({ approvedByKind: 'user' }, { $set: { approvedByKind: 'User' } })
0
votes

In my case, this issue because I haven't included the model or ref model into the application. So you should required Post model and Comment model in your node application.

0
votes

Refer the same name that you refer in model name while creating new model.

For example: if I have mongoose model like:

var Post = mongoose.model("post",postSchema);

Then I have to refer to posts collection via writing ref:"post".

0
votes

I also facing same issue but i resolved by removing module.exports

module.exports = mongoose.model('user', userSchema); // remove module.exports
and use like:: mongoose.model('user', userSchema);

const mongoose = require('mongoose');
const ObjectId = require('mongoose').ObjectId;

var userSchema = new mongoose.Schema({
    Password: { type: String },  
    Email: { type: String, required: 'This field is required.', unique:true },  
    songs: [{ type: ObjectId, ref: 'Songs'}]
});

// Custom validation for email
userSchema.path('Email').validate((val) => {
    emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return emailRegex.test(val);
}, 'Invalid e-mail.');

// module.exports = mongoose.model('user', userSchema);  // remove 'module.exports ='
mongoose.model('user', userSchema); // resolved issue
0
votes

My problem was sort out using the below

adminModel.findById(req.params.id).populate({ path: "users", model: userModel //User collection name })

0
votes

Just wanted to add that for me I was using destructuring when importing the Schema which was causing it to fail.

Correct

var intakeSchema = require('../config/models/intake')

Incorrect

var { intakeSchema } = require('../config/models/intake')
0
votes

You're not giving the model any value

In my case, I was using a model for which I didn't updated when making the MongoDB connection.

So, I had something like

const Device = require('../../models/device')
// make use of Device

with this connection

conn = await mongo.createConnection(conn,
      [JobApplication, Job, User])

Fix

You have to add the model to the conn when initiating the connection

conn = await mongo.createConnection(conn,
      [JobApplication, Job, User, Device])

Note that I added Device to the connection.