I need to create an account for a student and a teacher. Should I create two separate models in mongoose for student and teacher? What's the right approach? Student and teacher will share some properties and some will differ.
At this moment I have only one model for student and tutor:
const userSchema = new Schema({
name: {
type: String,
trim: true,
required: true,
maxLength: 32
},
surname: {
type: String,
trim: true,
required: true,
maxLength: 32
},
email: {
type: String,
unique: true,
trim: true,
required: true,
lowercase: true
},
isActiveTutor: {
type: Boolean,
default: false
},
birthCountry: String,
initials: String,
hashed_password: {
type: String,
required: true
},
salt: String,
role: {
type: String
},
teachingLanguage:{
type: Object,
/*language: {
language,
level,
price
}*/
},
resetPasswordLink: {
data: String,
default: ''
}
}, {timestamps: true});
But what if I wanted to give a teacher properties that a student would not have?
In case someone pass by here.
const options = {discriminatorKey: 'kind'};
const userSchema = new mongoose.Schema({/* user schema: (Common) */}, options);
const User = mongoose.model('User', userSchema);
// Schema that inherits from User
const Teacher = User.discriminator('Teacher',
new mongoose.Schema({/* Schema specific to teacher */}, options));
const Student = User.discriminator('Student',
new mongoose.Schema({/* Schema specific to student */}, options));
const teacher = new Teacher({/* */});
const student = new Student({/* */});
Original answer(modified): here.
Have a look at the docs here.
Related
What is the difference between this code:
const userSchema = new Schema(
{
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
phoneNumber: { type: Number, required: false, unique: true },
address: [{ type: mongoose.Types.ObjectID, required: true, ref: "Address" }],
},
{
timestamps: true,
}
);
And this code:
const userSchema = new Schema(
{
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
phoneNumber: { type: Number, required: false, unique: true },
address: { type: [mongoose.Types.ObjectID], required: true, ref: "Address" },
},
{
timestamps: true,
}
);
NOTICE:
In the first code, I surrounded the whole address object with square brackets.
In the second code, I only surrounded the type property of the address with square brackets.
What I want to know is how that will impact the app's behavior.
Is there any difference?
Thanks.
They both declare an array-of-references, but there are some subtle differences.
Let's take this simple schema:
const userSchema = mongoose.Schema({
address: { type: [ String ], required: true, default: undefined }
});
const User = mongoose.model('User', userSchema);
This will apply the options (required and default) to the address array-of-strings as a whole:
// This will fail validation:
// ValidatorError: Path `address` is required
const doc = new User({});
// This will pass validation:
const doc = new User({ address : [] });
Now change the position of the brackets in the schema:
const userSchema = mongoose.Schema({
address: [{ type: String, required: true, default: undefined }]
});
This will apply the options to the elements of the address array:
// This will pass validation, `address` itself isn't required:
const user = new User({});
// This will also pass validation, for the same reason:
const user = new User({ address : [] });
// This will fail validation, because elements of the array are required to have a proper value
// ValidatorError: Path `address.0` is required
const user = new User({ address : [ '' ] });
EDIT: if you want to enforce that the address field is always defined and has at least one element, you have to use a custom validator. For your schema, it would look like this:
address: {
type: [ mongoose.Schema.Types.ObjectID ],
ref: 'Address',
required: true,
default: undefined,
validate: a => Array.isArray(a) && a.length > 0
}
I'm working on a membership admin pannel and I'm required to do a custom membership ID asides from the _id itself.
My schema is actually looking like this:
const mongoose = require("mongoose");
const memberSchema = mongoose.Schema(
{
membershipId: {
/* AutoIncrement custom id */
type: Number,
default: 1,
unique: true,
index: true,
autoIncrement: true,
},
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
},
{
timestamps: true,
}
);
const Member = mongoose.model("Member", memberSchema);
module.exports = Member;
the point is that I would like to have something standarized by the company, such as... EMP-00001, EMP-000002, that autoincrements.
Is it possible? If so, how can I achieve this?
Thank you in advance.
I am new to mongoose js so i wanted to create a contact feild only one time the user fills a form
here is my contact model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ContactSchema = new Schema({
fname: {
type: String,
required: true,
default:"fname"
},
lname: {
type: String,
required: true,
default:"lname"
},email:{
type:String,
required: true,
default:""
},
mobile:{
type:Number,
required:true,
default:""
},
title:{
type:String,
required:true,
default:""
}
});
module.exports = Contact = mongoose.model('Contact', ContactSchema);
here is my user model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Link Schema
const LinkSchema = require('./Link').schema;
const ContactData=require('./conatct').schema;
// Create User Schema
const UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
lowercase:true,
trim: true,
},
email: {
type: String,
required: true,
unique: true,
trim: true,
lowercase:true
},
password: {
type: String,
required: true,
trim: true
},
resetToken:{type:String},
expireToken:{type:Date},
date: {
type: Date,
default: Date.now
},
theme: {
type: Number,
default: 1
},
avatar: {
type: String,
default: 'uploads/default.png'
},
displayname:{
type:String,
default:"",
trim:true
},
bio:{
type: String,
default: "",
},
title:{
type: String,
default: "",
},
links: {
type: [LinkSchema]
},
contact:{
type:[ContactData]
}
});
module.exports = User = mongoose.model('user, UserSchema);
** suggest me some queries for creating contact details only once the user enters the data i have tried from user.contact.push({}) but it creates multiple object in contact array**
If I get you, you want the contact field to be a single object not an array of objects then change
//change
contact:{
type:[ContactData]
}
//to
contact:ContactData
// when you want to add data you just do something like
const user = new User({
name,etc...,
contact.mobile:user_mobile, etc..
})
These the response for user that Im getting from get request to profile API
"user": "5cc3a4e8d37a7259b45c97fe"
What I'm looking for instead is
"user":{
"_id": "5cc3a4e8d37a7259b45c97fe",
"name":"Jhon Doe",
}
Here is my code:
Profile.findOne({
user: req.user.id
})
.populate('user',['name']) // I added this line to populate user object with name
.then(profile=>{
if(!profile){
errors.noprofile = 'There is no profile for this user'
return res.status(404).json(errors);
}
res.json(profile)
})
.catch(err => res.status(404).json(err));
However, Im getting these error:
{
"message": "Schema hasn't been registered for model \"users\".\nUse mongoose.model(name, schema)",
"name": "MissingSchemaError"
}
What am I missing
Profile Schema
const ProfileSchema = new Schema({
user:{
type: Schema.Types.ObjectId,
ref: 'users'
},
handle: {
type: String,
required: true,
max: 40
},
company: {
type: String
},
website: {
type: String,
}
})
Here is how my Users schema looks like
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const UserSchema = new Schema({
name:{
type: String,
required: true,
},
email:{
type: String,
required: true,
},
password:{
type: String,
required: true,
},
avator:{
type: String,
},
date:{
type: Date,
default: Date.now,
}
});
module.exports = User = mongoose.model('Users', UserSchema)
Schema that you are referencing in Profile schema is users, but you have saved your user schema as Users. So I would say that you need to update your Profile schema:
const ProfileSchema = new Schema({
user:{
type: Schema.Types.ObjectId,
ref: 'Users'
},
handle: {
type: String,
required: true,
max: 40
},
company: {
type: String
},
website: {
type: String,
}
})
Name under which is saved your User schema can be found in this line
module.exports = User = mongoose.model('Users', UserSchema)
The error says you don't have Schema for Users. You reference it from Profile Schema, but you don't have it. It can be this way:
const Users = new Schema({
name: String
})
I have defined a mongoose user schema:
var userSchema = mongoose.Schema({
email: { type: String, required: true, unique: true},
password: { type: String, required: true},
name: {
first: { type: String, required: true, trim: true},
last: { type: String, required: true, trim: true}
},
phone: Number,
lists: [listSchema],
friends: [mongoose.Types.ObjectId],
accessToken: { type: String } // Used for Remember Me
});
var listSchema = new mongoose.Schema({
name: String,
description: String,
contents: [contentSchema],
created: {type: Date, default:Date.now}
});
var contentSchema = new mongoose.Schema({
name: String,
quantity: String,
complete: Boolean
});
exports.User = mongoose.model('User', userSchema);
the friends parameter is defined as an array of Object IDs.
So in other words, a user will have an array containing the IDs of other users. I am not sure if this is the proper notation for doing this.
I am trying to push a new Friend to the friend array of the current user:
user = req.user;
console.log("adding friend to db");
models.User.findOne({'email': req.params.email}, '_id', function(err, newFriend){
models.User.findOne({'_id': user._id}, function(err, user){
if (err) { return next(err); }
user.friends.push(newFriend);
});
});
however this gives me the following error:
TypeError: Object 531975a04179b4200064daf0 has no method 'cast'
If you want to use Mongoose populate feature, you should do:
var userSchema = mongoose.Schema({
email: { type: String, required: true, unique: true},
password: { type: String, required: true},
name: {
first: { type: String, required: true, trim: true},
last: { type: String, required: true, trim: true}
},
phone: Number,
lists: [listSchema],
friends: [{ type : ObjectId, ref: 'User' }],
accessToken: { type: String } // Used for Remember Me
});
exports.User = mongoose.model('User', userSchema);
This way you can do this query:
var User = schemas.User;
User
.find()
.populate('friends')
.exec(...)
You'll see that each User will have an array of Users (this user's friends).
And the correct way to insert is like Gabor said:
user.friends.push(newFriend._id);
I'm new to Mongoose myself, so I'm not entirely sure this is right. However, you appear to have written:
friends: [mongoose.Types.ObjectId],
I believe the property you're looking for is actually found here:
friends: [mongoose.Schema.Types.ObjectId],
It may be that the docs have changed since you posted this question though. Apologies if that's the case. Please see the Mongoose SchemaTypes docs for more info and examples.
I would try this.
user.friends.push(newFriend._id);
or
friends: [userSchema],
but i'm not sure if this is correct.