117

I'm using 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 is causing the exception to be thrown?

Edit: Here's the exception error:

/home/me/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);
starball
  • 20,030
  • 7
  • 43
  • 238
arash moeen
  • 4,533
  • 9
  • 40
  • 85
  • 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 Nov 08 '14 at 14:29
  • @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 Nov 08 '14 at 14:30
  • @Umm. Did you ever "export" where you "required" later? I think that is the code that is missing here. – Neil Lunn Nov 08 '14 at 14:33
  • @NeilLunn you mean in the app.js? let me put the app.js code too (mongoose part only) – arash moeen Nov 08 '14 at 14:34
  • If that id your code then you never "exported" the model. Geez Three times now. You should get this by now. – Neil Lunn Nov 08 '14 at 14:37
  • @NeilLunn ok thanks, that's probably I'm still a newbie with this. I'll try to read more about exporting the model. thanks for giving me the direction – arash moeen Nov 08 '14 at 14:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/64537/discussion-between-arash-moeen-and-neil-lunn). – arash moeen Nov 08 '14 at 14:45
  • Did you manage to solve the problem? I am facing the same currently. – Prerak Sola Mar 19 '15 at 10:30
  • @PrerakSola Not really man, I had to drop it for a while since I was busy with another R&D to do. sorry – arash moeen Mar 19 '15 at 13:10
  • Well, I solved it finally. I followed the answer that is there to this question. It worked for me. – Prerak Sola Mar 19 '15 at 13:28
  • @PrerakSola aha then it should be a problem from my code although I've checked it with the answer if I remember correctly. But I'm glad his answer helped you. – arash moeen Mar 19 '15 at 14:10

21 Answers21

172

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();
Talha Awan
  • 4,573
  • 4
  • 25
  • 40
user8264
  • 1,878
  • 1
  • 11
  • 5
  • @Mark comment the var mongoose = require("mongoose"); and Comments and Posts similarly and then add var Posts = require("Posts"); directly inside the router.get and router.post , and similarly for Comments – Dhyey Jul 01 '16 at 07:24
  • This seemed to solve the Schema error, but now there's a "router is not defined" error in `routes/index.js`. I understand what a missing reference error is, but I thought that this didn't need to be instantiated.. anyone get this? – gin93r Jul 28 '16 at 16:25
  • @maiamachine Did you ever get the Thinkster tutorial to work? I've been working on it for about a week, and been stuck with random issues all over the place. Any chance you could post working code on [jsFiddle](https://jsfiddle.net/) or something? – Travis Heeter Jan 04 '17 at 02:16
  • @user8264: How to implement your concept for dynamically created schema model? – Pappa S Jun 03 '20 at 07:59
94

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'
}
Rafael Grilli
  • 1,959
  • 13
  • 25
  • 3
    fixed my issue :) – midhun k Aug 31 '19 at 06:00
  • I did something similar and it also fixed the problem...In the user model I changed the line: module.exports = mongoose.model('User', UserSchema) -->"user" with capital U to module.exports = mongoose.model('user', UserSchema) --->"user" with lower case u – chu8 Jun 01 '22 at 12:01
  • 1
    Thank you, i was referencing 'users' instead of 'user' lol. – PAUL Jun 24 '22 at 06:26
75

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' },
});

// model creation - notice the registered model name as first parameter
var User = db1.model('_users_', userSchema);
var Customer = db2.model('_customers_', customerSchema);

Correct approach:

// you can pass a model instance
Customer.findOne({}).populate('created_by', 'name email', User)
Customer.findOne({}).populate({ path: 'created_by', select: 'name email', model: User })

// you can pass the model NAME as string (even from variable)
Customer.findOne({}).populate('created_by', 'name email', '_users_')
Customer.findOne({}).populate({ path: 'created_by', model: '_users_' })

var otherSchemaName = '_'+'users'+'_'
Customer.findOne({}).populate({ path: 'created_by', model: otherSchemaName}) 

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

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

It seems Mongoose have now included this case in their docs based on this answer ;) see: https://mongoosejs.com/docs/populate.html#cross-db-populate

user3616725
  • 3,485
  • 1
  • 18
  • 27
24

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.

kuldipem
  • 1,719
  • 1
  • 19
  • 32
11

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);
Nikhil Vats
  • 291
  • 3
  • 7
  • This worked for me. I'm using models from two separated sources; some models from a custom library, and others from my local project. – José Pulido Dec 15 '21 at 04:33
9

this problem happens 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,
    },
  });
scr2em
  • 974
  • 8
  • 17
4

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);

HK boy
  • 1,398
  • 11
  • 17
  • 25
100RaBH
  • 161
  • 3
  • I had the same problem while a model refers to another mongoose model. Inspired by your answer, change to the correct MongoDB collection name which my current MongoDB collection refers to. Problem solved. Thank you very much. – GoodApple Aug 05 '19 at 07:34
4

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

});

ajay
  • 41
  • 1
2
.\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);
Visv M
  • 431
  • 4
  • 13
2
import User from '..'

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

This answer works for me. However You're going to have to import the model instead of setting it into cote

mr_a_top
  • 61
  • 3
1

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

Akash Das
  • 11
  • 3
0

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

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' } })
developius
  • 1,193
  • 9
  • 17
0

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.

Thai Ha
  • 1,331
  • 14
  • 21
0

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".

Theo
  • 57,719
  • 8
  • 24
  • 41
Drumil
  • 1
0

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
HSP
  • 345
  • 4
  • 4
0

My problem was sort out using the below

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

Hemant
  • 95
  • 5
0

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

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.

Gabriel Arghire
  • 1,992
  • 1
  • 21
  • 34
0

I just face the same problem. I created reviews for products. then I deleted them. whenever mongoose tried to populate the data of deleted items Mongoose Schema hasn't been registered for model error was showing. After dropping the review collection the error was gone.

0

For anybody else watching this in the future, another potential cause for this error is when mongoose.model(modelName, modelSchema) is not yet called for the model you are trying to populate (The model you mentioned in ref). This usually happens when you define your models in separate files. To resolve this issue, make sure always to import the file containing the definition for the model being populated before populating