简体   繁体   中英

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.

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!

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.

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.

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

In my case, it happened because of capital/small letter confusion. User model had this:

const userSchema = new Schema({
// ...
});
module.exports = mongoose.model('User', userSchema);

And Product model had a reference to User model but small case:

const productSchema = new Schema({
// ...
  userId: {
    type: Schema.Types.ObjectId,
    ref: 'user', // This should exactly match the name of User model above!!!
    required: true
  }
});

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']
}

I've also experienced this error with ES6/Typescript. Even I imported the model, the error still persisted. According to docs here

MongooseError.MissingSchemaError

Thrown when you try to access a model that has not been registered yet

    import { model, Schema } from 'mongoose';
    import Company from './CompanyModel';

    const ProjectSchema = new Schema({
        company: { type: Schema.Types.ObjectId, ref: "Company" }
    });

    export default model('Project', ProjectSchema);

The tips was just to make sure to use the model explicitly, so changing ref:"Company" into ref:Company.modelName seemed fixed it.

I hope that helps some of you

  • You'll need to require your model in your code
  • Mongoose won't recognize that you've defined a model until you've called mongoose.model, and that's only called when you require model

Ex.

In the below example, you will get MissingSchemaError: Schema hasn't been registered for model “Role” if you don't do const Role = require("./role");

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const Role = require("./role");
const userSchema = new Schema(
  {
    role: { type: Schema.Types.ObjectId, ref: "Role", required: false },
    username: { type: String, required: true, trim: true },
    password: { type: String, required: true, trim: true },
    email: { type: String, required: true, trim: true }
  },
  { timestamps: true }
);

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

In using express, one of the common mistake is by requiring the express before mongoose. This results to "MissingSchemaError: Schema hasn't been registered for model "User"." error.

You can easily fix it by correcting the "require" order (ie mongoose then express)

var mongoose = require('./config/mongoose'), 
    express = require('./config/express');

I got this error while trying to use mongoose-fixture to seed some default data into a mongo collection. Was baffled for long, following this and similar threads for help, trying to debug. Ultimately the issue turned out to be due to mongoose and mongoose-fixture versions in my case.

If no code changes help, or if you get this error while trying to correctly use mongoose-fixture (which is supposed to register your schemas for you), try this. Delete the node_modules dir of your project, run an npm cache clean , and then an npm install .

If even this doesn't help, try comparing versions of mongoose / mongoose-fixture between the problematic app and one that works, and try changing the version in your package.json , and repeating the above steps. This worked for me.

I recently came across a solution similar to the answers provided by @rajkumar-nagarajan and @verybadalloc.

I like this approach better, because it avoids the n+1 iteration, and it does not read all the models from the file system.

In app/models/index.js , require each model file:

require('./model1');
require('./model2');
require('./model3');

Then, in /app.js or /index.js (whichever your project uses), you can now simply do:

require('./app/models');

The part I'm missing (any tips appreciated here) --how to easily register each model by name like:

mongoose.model('Model1')

I was making a different mistake like I have created the Schema but the issue was that I didn't use schema model (for insert, update, read and delete the doc).

ie I have created the collection something like that:

const playerSchema = new Schema({
    bowling: {
        style: String,
        arm: String,
    }
})

export const PlayerSchema = model('Player', playerSchema)

but didn't use or call PlayerSchema model somewhere that's why I was getting this error.

I encountered this issue when tried to add a new model on the base code of this tutorial User Auth on MEAN stack . The solution is like what Ahei mentioned.

Specifically, I need to add a line require('path/to/your/model') in the end of /app_api/models/db.js which is required in the app.js . It is better to keep the consistency of the structure for the ease of development.

我尝试了上述所有解决方案,但都失败了,我发现解决方案是清除我的数据库(MongoDB),然后重新运行应用程序

The problem arises in the require() statements for the models. You need to move all the MongoDB dependencies above the routes dependencies like this eg

//blog.js file

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

const blogSchema = new Schema({
title : String
});

mongoose.model('blogs', blogSchema);

in server.js

//server.js file
require('dotenv').config();
const mongoose = require('mongoose');
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
require('./models/blog');
const Blog = mongoose.model('blogs');

const URL = process.env.MONGO_DB_URL;
 mongoose.connect(URL, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

mongoose.connection
.once('open', () => console.log('Connected to MongoLab instance.'))
.on('error', (error) => console.log('Error connecting to MongoLab:', error));

const app = express();

app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get('/',  (req,res)=>{
res.send('Hello World')
});

 app.post('/blog',async (req, res) =>{
    const blog = await new Blog(req.body).save();
    res.send('just an example');
  });

If you are facing this error because of ref field in your schema, you need to provide exact name that you used for that modeling reference schema (its case sensitive).

// models/User.js
const userSchema = new Schema({ name: String });
module.exports = mongoose.model('User', userSchema); // note the 1st arg


// models/Post.js
const postSchema = new Schema({ 
   user: { 
     type: mongoose.Schema.Types.ObjectId, 
     ref: 'User' // `ref` must be 'User' not 'user'
   },
})

module.exports = mongoose.model('Post', postSchema)

Also while calling .populate() on query, the reference model must be modeled before calling it. This is because models/User.js is not executed anywhere else in here, so by importing you will make User available in mongoose.models object.

In a real project the User model file be imported at least once through out the project, so just make sure you have imported reference model at least once.

// your app
const User = require('./models/User') // important to import
const Post = require('./models/Post')

//console.log(!!mongoose.models.User) // true
//..
const post = await Post.findOne().populate({ path : 'user' })

Alternative way is to import User model in Post model and use it for ref field.

// models/User.js
const userSchema = new Schema({ name: String });
module.exports = mongoose.model('User', userSchema);


// models/Post.js
const User = require('./User')

const postSchema = new Schema({ 
   user: { 
     type: mongoose.Schema.Types.ObjectId, 
     ref: User, // here we are directly referring model instance itself instead of model name.
   }
});

module.exports = mongoose.model('Post', postSchema)

& of course there are many approaches for solving this issue.

If you are using the Mean.js stack, run the test with:

grunt test

And not with

mocha

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM