MissingSchema Error: Schema hasn't been registered for model "User" - javascript

I keep getting this error whenever I launch my application:
--MissingSchema Error: Schema hasn't been registered for model "User" --
I'm working a tutorial from the "Mongoose for Application Development" book by Simon Holmes.
I'm at Chapter 5 "Interacting with Data - Creation"
Here's my code:
app.js:
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, project = require('./routes/project')
, http = require('http')
, path = require('path');
db.js:
//Creating the Application Schemas:
//====================================
//User Schema:
//===============
var userSchema = new mongoose.Schema({
name: String,
email: {type: String, unique:true},
createdOn: { type: date, default: date.now },
modifiedOn: Date,
LastLogin: Date
});
//Build the User Model:
//===========================
mongoose.model( 'User', userSchema );
User.js:
var mongoose = require("mongoose");
var User = mongoose.model( 'User' );
ERROR THAT RESULTS:
throw new mongoose.Error.MissingSchemaError(name);
^
MissingSchemaError: Schema hasn't been registered for model "User".
Use mongoose.model(name, schema) at Mongoose.Model (C:\Users\New\Desktop\mongoose_pm_app\
mongoosepm\node_modules\mongoose\lib\index.js.311.13)
at Object. <anonymous> (C:\Users\New\Desktop\mongoose_pm_app\mongoosepm\routes\user.js:2:21)
atModule._compile (module.js:456:26)
atObject.Module._extensions..js (module.js:474:10)
atModule.load (module.js:356:32)
at Function.Module._load (module.js:364:17)
at require (module.js:380:17)
at Object <anonymous> (C:\Users\New\Desktop\mongoose_pm_app\mongoosepm\app.js:8:12)
at Module._compile (module.js:456:26)
25 June 19:52:55 - [nodemon] app crashed waiting for file changes before starting...
I'm young to mongoose and mongodb.
I've been through the books errata pages to
check if I mistyped anything but its all the same as here.
I also tried downloading the sample code from PACKT, the sample code
looks the same.
Any and all assistance would be Greatly appreciated.
Thanks.

You need to require your db.js file someplace, as otherwise the code in it will never run, and the schema will never be registered.
Also, I would recommend that you define your user schema inside of User.js and add the model to exports, like so:
User.js
//User Schema:
//===============
var userSchema = new mongoose.Schema({
name: String,
email: {type: String, unique:true},
createdOn: { type: date, default: date.now },
modifiedOn: Date,
LastLogin: Date
});
//Build the User Model:
//===========================
var User = mongoose.model( 'User', userSchema );
//Exports
//=======
exports = User;
This allows you to do just require the file elsewhere to get a reference to the User model (instead of having to retrieve it through mongoose.model). For example:
var User = require('User');
// ...
var fred = new User({ ... }); // create a new user
fred.save(function (err, user) { ... });
I've not read the book that you referred to, so I'm not sure if there might be a good reason to define all your schemas in one file (which is the direction it looked like you were going in with db.js). From what I've seen, it's more common to have one schema/model per file.

That error comes from one line:
var User = mongoose.model( 'User' );
You need to provide a Schema object to mongoose.model() method. The first param, 'User', just tells mongoose in what will the collection be named. The second one defines the user schema.
So either do something like Sergey has answered, or add these few changes.
To your db.js, add export line at the bottom:
module.exports = userSchema;
Then require it in User.js:
var mongoose = require("mongoose");
var userSchema = require("./db.js");
var User = mongoose.model( 'User', userSchema );
module.exports = User;
Alternatively you can just alter the last line in your Schema definition, by exporting the user model when you build it:
//Build the User Model:
//===========================
module.exports = mongoose.model( 'User', userSchema );
Then you don't need User.js at all.
Although, then your file naming doesn't follow convention, if you care about it.
Advantages of separating Schema and Model are when you require multiple complex schemas, when you have a lot of schema plugins so you want a simpler model file where you require all that. If you only have a simple schema like above, I recommend that you use a single-file version.

Related

'this' is empty during Mongoose middleware

long time Java programmer here trying to figure out Node.js
I am trying to cascade a delete to child objects using the pre middleware, but no child delete is happening, while the parent deletes without a hitch. Leaving my database full of sad orphans. When I started logging to the console I see that the reference to 'this' is empty. For most cases this seems to be a problem of using ==> to create the function, but I am not doing so:
GameSession(parent):
var mongoose = require('mongoose');
var TimeLineEvent = require('../models/timelineevent');
//Define a schema
var Schema = mongoose.Schema;
var GameSessionSchema = new Schema({
name: {type: String, required: true},
gameMasterId : {type: Schema.Types.ObjectId, ref: 'GameMaster', required: true},
});
GameSessionSchema.pre('findOneAndDelete', function(next) {
console.log('GameSessionSchema.pre findOneAndDelete this ='+this);
console.log('GameSessionSchema.pre findOneAndDelete id ='+this._id);
TimeLineEvent.deleteMany({gameSessionId: this._id}).exec();
next();
});
//Export function to create "SomeModel" model class
module.exports = mongoose.model('GameSessionModel', GameSessionSchema );
TimeLineEvent(child):
//Require Mongoose
var mongoose = require('mongoose');
//Define a schema
var Schema = mongoose.Schema;
var TimeLineEventSchema = new Schema({
name: {type: String, required: true},
gameSessionId: {type: Schema.Types.ObjectId, ref: 'GameSession', required: true},
time: {type: Number, required: true},
nextAction: {type: Number}
});
module.exports = mongoose.model('TimeLineEventModel', TimeLineEventSchema );
This is what the console shows when the pre method is called:
GameSessionSchema.pre findOneAndDelete this =[object Object]
GameSessionSchema.pre findOneAndDelete id =undefined
Can you see what I am missing? Thanks!
From the documentation: "In query middleware functions, this refers to the query."
If you use console.log(this) you will be able to view the full Query object. You might find this.model references what you need.

Populating an Object with Information from a Child Object with Different Model (JS/Mongoose)

Here is what I have. I created a project model that references a user model for an array of members.
var ProjectSchema = new mongoose.Schema(
{title: {
type: String,
required: true
},
members: [
{user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'users'
}
}],
});
User Schema (I have code that creates a model from both of these schemas)
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
}
});
In a separate file, I want to export the JSON of a found project and include the information of the users in the members array, but I am not sure how to do that. This is the code I have right now.
const project = await Project.findById(req.params.proj_id).populate(
'members'
);
res.json(project);
It has no trouble finding the project but the only information I can get on the members is their id. I tried using for loops to gather the information from members separately using the id that I can get from the project, but the code gets messy and I am hoping to find a simpler way to do it.
You can use mongoose populate query to get all members associated with a project. It should populate array of objects users associated to a project. You should be doing something like this:
const project = await Project.findById(req.params.proj_id)
await project.populate('members').execPopulate()
console.log(project.members)
Mongoose docs for the reference: Populate
You can give the model to your mongoose populate.
const project = await Project.findById(req.params.proj_id)
.populate({
'members',
model: UserModel
})
.exec()
res.json(project);
keep in mind you've to create UserModel just like
const UserModel = mongoose.model('User', userSchema);

Using 2 connections in mongoose in nodeJS

I want to use 2 or more different databases simultaneously, these 2 connections have different properties. And according to database selection data should be displayed. Its dynamic db switch in mongoose if anyone have any idea please help.
Lets say there is a model
var mongoose = require('mongoose');
var Promise = require("bluebird");
mongoose.Promise = Promise;
var Schema = mongoose.Schema;
var uomSchema = new Schema({
uom: {
type: String,
required: [
true,
"Please enter valid uom"
],
elementType: "TEXT",
elementText: "Unit Of Measure",
placeholder: ""
}
}, { strict: false });
var uom = mongoose.model('uom', uomSchema);
module.exports = uom;
so here it creates model over default connection foo, so if there is another connection bar and over that db needs to create same model to operate over data, how is that possible ?
mongoose-glue provide somewhat similar solution, but not exact that I want
Maintain one json file in that { "db1":"asas" , "db2":"xczc" } and while connecting to db fetch db name from this json file as
var conUrl = config.db1 OR db2 as per your condition

Load only required plugin into the Schema when saving a model

Plugins is quite a powerful feature in Mongoose.js, but there is one thing I have got stuck with. I need to load only the required plugin into the Schema when saving a model. Because If I don't do it, the other unnecessary plugins are loaded automatically along with lots of validation errors.
Here is my schema
// models/user_collection.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: { type: String, required: true },
password: { type: String, required: true },
role: String // either 'memeber' or 'admin'
});
// Member User Plugin
UserSchema.plugin(function (schema) {
schema.add({
locality: { type: String, required: true },
contactNo: { type: Number, min: 13, max: 13 }
});
});
// Admin User Plugin
UserSchema.plugin(function (schema) {
schema.add({
accountNo: { type: String, required: true },
settingsArray: Array
});
});
mongoose.model('User', UserSchema);
Now whenever I try to save a record only for member user, the Schema automatically loads the Admin plugin, responding with validation errors.
So,
var member = new User();
member.username = 'XYZ';
member.password = createHash('ABC') // a hashing method;
member.role = 'member';
member.locality = 'USA';
member.contactNo = 123456;
member.save(function(err, user) {
if(err) { console.log(err); res.send(err); return; }
// if successful I do my stuff
});
As soon as the save method is executed, I get validation errors from Admin like
"accountNo is required", ( I am not gonna paste the stack trace here, it will get messy, but you got the point )
Now I know that it is not an issue or bug with Mongoose.js, but I am doing something wrong here. Can you guys please guide me how to do it correctly ?
The thing is you are applying both the plugins to the same schema. So all the plugin functionality is being added to the schema. So accountNo and locality is required. Plugins are used to define common code at one place and use it across different schemas.
The way you have used plugins here, you just have broken down the definition of the model to smaller parts. You could as well put everything under the schema and would have gotten the same effect.
Read about plugins again.
As you said, I guess Discriminators is the way to go.

Remove embedded document in mongoose

I'm new to node.js and MongoDB. I'm using the Mongoose Library for accessing MongoDB with node.js.
I have two Schemas, Book and Author. Author belongs_to a Book and Book has_many Author.
I have this in my schemas:
var mongoose = require( 'mongoose' );
var Schema = mongoose.Schema;
var Book = new Schema({
title : String,
isbn : String,
authorId : [{ type: Schema.Types.ObjectId, ref: 'Author' }],
updated_at : Date
});
var Author = new Schema({
name : String,
updated_at : Date
});
mongoose.model( 'Book', Book );
mongoose.model( 'Author', Author );
mongoose.connect( 'mongodb://localhost/library' );
The problem is that when I delete a document from Author which is embedded with Book it is deleted without checking the referential integrity. My scenario is that if the Author document is embedded with the Book it can't be deleted. Is Mongoose automatically check the author document embedded in the book ? Is it possible? then how?
You can try the following code for the schema you mentioned.
Author.pre('remove', function(next) {
Author.remove({name: this.name, updated_at: this.updated_at }).exec();
Book.remove({authorId : this._id}).exec();
next();
});
More info on SchemaObj.pre(method,callback)

Categories