Mongoose - Multiple models for 1 schema - node.js

I am using mongoose v5.2.17.
I was wondering is it possible to have multiple models map to the 1 schema.
For example - I have the following model
const mongoose = require('mongoose');
const validator = require('validator');
const jwt = require('jsonwebtoken');
const _ = require('lodash');
const bcrypt = require('bcryptjs');
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true,
trim: true,
minlength: 1,
unique: true,
validate: {
validator: validator.isEmail,
message: '{VALUE} is not a valid email',
},
},
password: {
type: String,
required: true,
minlength: 6,
},
isTrialUser: {
type: Boolean,
default: true,
},
isAdminUser: {
type: Boolean,
default: false,
}
});
UserSchema.methods.toJSON = function () {
const user = this;
const userObject = user.toObject();
return _.pick(userObject, ['_id', 'email', 'isTrialUser']);
};
UserSchema.pre('save', function (next) {
const user = this;
if (user.isModified('password')) {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (hashErr, hash) => {
user.password = hash;
next();
});
});
} else {
next();
}
});
const User = mongoose.model('User', UserSchema);
module.exports = { User, UserSchema };
Is it possible for me to create another AdminModel where admin specific methods can live?
I also want to return all data from the toJSON method from the AdminModel.
Please let me know if this is possible or if there is a better way to perform such a task
Thanks
Damien

If I am understanding you correctly you want to inherit the UserModel in an AdminModel and decorate that one with extra methods etc. For that you can use util.inherits (or the so called Mongoose discriminators) like so:
function BaseSchema() {
Schema.apply(this, arguments);
this.add({
name: String,
createdAt: Date
});
}
util.inherits(BaseSchema, Schema);
var UserSchema = new BaseSchema();
var AdminSchema = new BaseSchema({ department: String });
You can read more about it in Mongoose docs.
There is also a good article on the mongoose discriminators here

Related

Circular Dependency Error for deleteMany MongoDB

I am writing the Model for my Web App API, and am getting the following circular dependency error:
Warning: Accessing non-existent property 'deleteMany' of module exports inside circular dependency
(Use node --trace-warnings ... to show where the warning was created)
.
Here is my code:
const validator = require('validator')
const bcrypt = require('bcrypt')
const jwt = require('jsonwebtoken')
const Task = require('./task')
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const userSchema = new Schema({
email: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid.')
}
}
},
password: {
type: String,
required: true,
trim: true,
minLength: 8
},
name: {
type: String,
unique: true,
required: true,
trim: true
},
tokens: [{
token: {
type: String,
required: true
}
}]
})
userSchema.pre('save', async function(next) {
const user = this
if (user.isModified('password')) {
user.password = await bcrypt.hash(user.password, 8)
}
next() // run the save() method
})
userSchema.pre('deleteOne', {document: true, query: false}, async function(next) {
const user = this
await Task.deleteMany({owner: user._id})
next()
})
userSchema.methods.toJSON = function() {
const user = this
const userObject = user.toObject()
delete userObject.password
delete userObject.__v
delete userObject.tokens
return userObject
}
userSchema.methods.generateAuthToken = async function () {
const user = this
const token = jwt.sign({ _id: user._id.toString() }, process.env.JSON_WEB_TOKEN_SECRET)
user.tokens = user.tokens.concat({ token })
await user.save()
return token
}
userSchema.statics.findByCredentials = async (email, password) => {
const user = await User.findOne({email})
if (!user) {
throw new Error('Unable to login')
}
const isMatch = await bcrypt.compare(password, user.password)
if (!isMatch) {
throw new Error('Unable to login')
}
return user
}
userSchema.virtual('tasks', {
localField: '_id',
foreignField: 'owner',
ref: 'Task'
})
const User = mongoose.model('User', userSchema);
module.exports = User
Any idea what could be going wrong? I have checked my Node.js and MongoDB versions and updated them, but continue to get this same error when I try to delete. I can provide further details of my code if necessary. The problem area in question is the one leading with userScheme.pre('deleteOne'....

When making a POST request for a subdocument it comes back as undefined? mongoose, express

I'm trying a to make a post request to save new data to one of my subdocuments, but I'm getting an error when trying to access the subdocument in the function. It keeps coming back as undefined. How can I get a specific user by id and create and add new data the one it's subdocuments?
model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const ClassworkSchema = new Schema({
name: String,
time: Date,
todo: String,
isDone: false
});
const OutcomesSchema = new Schema({
name: String,
time: Date,
todo: String,
isDone: false,
isApproved: false
})
const MeetupSchema = new Schema({
name: String,
time: Date,
location: String,
attended: false
})
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
classwork:{type: [ClassworkSchema], default: []},
outcomes: [OutcomesSchema],
meetups: [MeetupSchema],
});
module.exports = User = mongoose.model('users', UserSchema);
controller
classworkRouter.post("/:userId/", (req, res) => {
User.findById(req.params.user_id, (err, user) => {
if (err) return err;
new_classwork = new classwork();
(new_classwork.name = req.body.name),
(new_classwork.date = req.body.date),
(new_classwork.todo = req.body.todo),
(new_classwork.isDone = req.body.isDone);
console.log(new_classwork);
user.classwork = {};
user.classwork.name = req.body.classwork.name;
user.classwork.todo = user.classwork.todo;
if (user.classwork === undefined) {
user.classwork.push(new_classwork);
} else {
user.classwork = [new_classwork];
}
user.save(function (err, data) {
if (err) res.send(err);
res.json({ message: "work added", data: data });
});
});
});
you can see the error in the terminal in the following phto:
in this part of code
new_classwork = new classwork()
you shoud defined the new_classwrok like this :
let new_classwork = new classwork()
and new classwork() is not defined, you must to require Model of classwork in controller..
in schema file export schemas like this :
const User = mongoose.model('users', UserSchema);
const Classwork = mongoose.model('Classwork', ClassworkSchema );
module.exports = {
User : User ,
Classwork : Classwork
}
in controller.js
const {User} = require('../models/certification');
const {Classwork } = require('../models/certification');
after require models you can use new Crosswork like this :
note: Classwork with uppercase character
let new_classwork = new Classwork()

schema.methods is not a function

I have been trying to create a method on my user schema in mongoose, however it keeps saying method is not a function and I have no idea why. I am fairly new to mongoose and express, and I'm pretty sure I have my files set up currently so I don't know what could be causing this issue. As a last attempt, I tried switching to arrow functions , but that didn't work either.
user routes file
const router = require("express").Router();
let user = require("../models/user_model");
const Joi = require("#hapi/joi");
// GET dreams
// POST dreams
// DELETE dreams
// UPDATE dreams
router.route("/").get((req, res) => {
console.log(user.addType());
res.send("hello this is a users page");
});
user model file
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema(
{
username: {
type: String,
required: true,
unique: true,
trim: true,
min: 3
},
password: {
type: String,
trim: true,
required: true,
min: 6
}
},
{
timestamps: true
}
);
userSchema.methods.addTypes = function() {
console.log("woof");
};
userSchema.methods.joiValidate = data => {
let Joi = require("#hapi/joi");
const schema = {
username: Joi.string()
.min(6)
.required(),
password: Joi.string()
.min(6)
.required()
};
return schema.validate(data);
};
module.exports = mongoose.model("User", userSchema);
UPDATE! Other than having typo on your code, you also need to create an instance of your model ('user'). You cannot just call the function of the model.
let user = new user({ // Create an instance first
username: 'Tester',
password: '12345678'
})
console.log(user.addType())
you declared
addTypes()
Cheers

Mongoose Model.findOne not a function

Having an issue with a model. Trying to do a model.findOne(), but I keep getting the error
TypeError: User.findOne is not a function
I have the model setup like so:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
firstName: String,
lastName: String,
emailAddress: {
type: String,
required: true,
unique: true
},
userName: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
});
module.export = User = mongoose.model("User", UserSchema);
and I have it imported in the file that I want to find a user:
const { Strategy, ExtractJwt } = require("passport-jwt");
const log = require("./logger");
require('dotenv').config();
const fs = require("fs");
const secret = process.env.SECRET || 'thisneedstob3ch#ng3D';
const mongoose = require("mongoose");
const User = require("./models/user");
const opts = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: secret
};
module.exports = passport => {
passport.use(
new Strategy(opts, (payload, done) => {
User.findOne({id: payload.id})
.then(user => {
if (user) {
return done(null, {
id: user.id,
name: user.name,
email: user.email
});
}
return done(null, false);
})
.catch(err => log.error(err));
})
);
};
Regardless, I get the error. I've tried .findById() as well as .findOne()
Is there something I'm missing?
You made a typo in you user.js file, you forgot the s of module.exports:
module.exports = User = mongoose.model("User", UserSchema);

Mongoose userModel is not defined

I'm pretty new with nodejs and mongoDB. I have created a registration and user schema but it doesn't recognize this and send the following error:
ReferenceError: userModel is not defined
When I trace the error, I found that it doesn't recognize this keyword.
Here is user.js code:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt');
var userSchema = new Schema({
teamName: {
type: String,
unique: true,
trim: true,
required: true
},
faculty: {
type: String,
required: true
},
email: {
required: true,
unique: true,
trim: true,
type: String
},
password: {
required: true,
type: String
},
score: {
type: Number,
default: 0
}
});
userSchema.pre('save', function(next) {
var user = this;
bcrypt.hash(user.password, 10, (err, hash) => {
if (err) return next(err)
user.password = hash;
next();
});
})
var userModel = mongoose.model('User', userSchema);
module.exports = userModel;
server.js
router.post('/register', (req, res) => {
var newUser = {
teamName: req.body.teamName,
faculty: req.body.faculty,
email: req.body.email,
password: req.body.password
}
userModel.create(newUser, (err, user) => {
if (err) {
console.log('[Registratoin]: ' + err);
} else {
console.log(user)
console.log('[Registration]: Done');
// req.session.userID = user._id;
res.redirect('/scoreboard')
}
});
});
The this keyword in the pre-save hook in your model is not the issue.
ReferenceError: userModel is not defined
ReferenceError: "x" is not defined means that the userModel is undefined from the scope you're calling it from. (Thus you're referencing a non-existent value)
I have include it like var userModel = require('the_path')
As you're requiring and exporting the userModel correctly. I would double check the path you're importing the module from.

Resources