I have the following mongoose schemas for a MongoDB:
User
{
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
...
}
userSchema.methods.verifyPassword(password) {
//Verify password match
}
Customer
{
user: [User],
firstname: { type: String, required: true },
lastname: { type: String, required: true },
...
}
Company
{
user: [User],
name: { type: String, required: true },
...
}
I've decided to store the models 'Customer' and 'Company' in the same collection 'Users', as they are account data with only a few different attributes.
I'm implementing a method for login. The problem came when I try to verify the password, how can I implement a unique method for getting this embedded user.password?
Company.findOne() seems to work and Customer.findOne() too. How do I choose one? (I don't know if the login is for a company or customer, only have the email and password). If I try to implement a User model and later User.findOne(), then I can't access user.user.password due to the schema User.
Is there a right way to do it that I am not seeing?
Related
I am trying to define a conditional required field for a mongoose model in the following way:
const userSchema = new mongoose.Schema({
email: {
type: String,
},
emailVerified: {
type: Boolean,
required: true
},
hash: {
type: String,
required: function() {
if(!this.emailVerified) return true
return false
}
},
oauth: {
type: Boolean,
required: true,
},
password: {
type: String,
required: function() {
if(this.oauth) return false
return true
}
}
})
export default mongoose.models.Users || mongoose.model('Users', userSchema)
My intention is that I only want the hash field to be required when emailVerified === false, and the password field to be required only when oauth === true.
The thing is that when I try to add a document in the Users collection I get the following error:
Error: Users validation failed: hash: Cannot read property 'emailVerified' of undefined, password: Cannot read property 'oauth' of undefined
By looking at the documentation I understand that I should be able to reference the model in its own definition.
This question was asked several times, but despite that, I wasn't able to solve my problem. In my mongoose collection, I store 30 users with the following mongoose schema. I want to implement a newsletter on my site, therefore I want to add the new field:
newsletter: {
type: Boolean,
default: true
},
My question is: How can I add newsletter false/true to every user?
I found that, but it didn't work.
User.updateMany({}, [{ $set: { newsletter: false }}])
My Schema:
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
date: { type: Date, default: Date.now },
token: { type: String, required: true }
});
const User = mongoose.model('User', UserSchema);
module.exports = User;
Adding to the schema "newsletter" does solve the problem for new users, but doesn't add the field to the already existing ones.
I have a field called mail as unique in MongoDB.
I'm trying to update the user but it happens that if I don't change the mail field it tells me it's a duplicate. I need it not to be necessary to always change the email because sometimes they just want to change another field.
This is my model:
import { Schema, model } from "mongoose";
const UserSchema = Schema (
{
username: {
type: String,
maxlength:50,
required: [true, 'El Nombre de Usuario es obligatorio'],
unique: true
},
name: {
type: String,
maxlength:50,
required: [true, 'El Nombre es obligatorio']
},
lastName: {
type: String,
maxlength:50,
required: [true, 'El Apellido es obligatorio']
},
mail: {
type: String,
required: [true, 'El Correo es obligatorio'],
unique: true
},
password: {
type: String,
required: [true, 'La ContraseƱa es obligatorio']
},
picture:{
path: {
type: String
},
originalName: {
type: String
}
},
role: {
type: String,
required: true,
enum: ['ADMIN_ROLE', 'USER_ROLE', 'SUPER_ROLE', 'SELLER_ROLE', 'WAREHOUSE_ROLE', 'WAREHOUSE_ASSISTANT_ROLE', 'SALES_ROLE', 'PURCHASES_ROLE','CASH_ROLE']
},
status: {
type: Boolean,
default: true
},
createdBy:{
uid : { type: String, required: true },
username:{ type: String, required: true }
},
createdAt: {
type: Date,
default: Date.now
}
}
);
module.exports = model('Users', UserSchema);
This is my function where I update but it returns the error of duplicate key in mail.
const updateUser = async (req, res = response) => {
let id = req.params.id;
let { _id, password, ...data } = req.body;
if ( password ) {
let salt = bcrypt.genSaltSync(15);
resto.password = bcrypt.hashSync( password, salt );
}
let lastModificationByUser = {
uid: req.uid,
username: req.user.username,
comments: data.comments
};
let user = await User.findByIdAndUpdate( id,
{
$set: data,
$push: {
'lastModificationBy': {
$each: [lastModificationByUser],
$slice: -5
}
}
},{ new: true }
);
res.json({
user
})
}
But I get the following error:
Thanks for your help.
Understand unique
if you create a user with a unique email address and then update their email address to a non-unique value (same email address), you'll get the dup key error.
if you insert a user with the email address empty, and you try to create another user with the email address empty, you will also get the dup error.
In your case
Remove the mail field from your data object, unless you are updating the user with a new unique email address.
DO NOT TRUST ANYTHING SUBMITTED CLIENT SIDE
let { _id, password, ...data } = req.body;
Destructuring and then updating the data field directly to the model is not safe. (e.g. even if your form does not contain the password field)
For example, I can send a post request with curl or postman with the password field, and you will be updating the password too without knowing.
What you should do
const { name, lastname, picture } = data;
const update = { name, lastname, picture }
let user = await User.findByIdAndUpdate( id, update );
PS: this is just an example, though in your codes you already conditionally check your password.
I have three models: User, Teacher and a Student. A user can either be a teacher or a student depending upon the role.
Now, I would like to populate the Teacher and the Student model as the User model gets populated. This is the query that I am using which isn't populating the Teacher model. (And the student model as well on the other condition)
const user = await User.create({
...userDetails
include: [Teacher]
})
User Model:
const User = connObj.define('user', {
name: {
type: Sequelize.TEXT,
allowNull: false
},
username: {
type: Sequelize.STRING(50),
allowNull: false
},
email: {
type: Sequelize.TEXT,
allowNull: false
},
password: {
type: Sequelize.STRING(100),
allowNull: false,
set (password) {
const passHash = bcrypt.hashSync(password, salt)
this.setDataValue('password', passHash)
}
},
isTeacher: {
type: Sequelize.BOOLEAN,
defaultValue: false
}
})
Teacher Model:
const Teacher = connObj.define('teacher', {})
And the relation is
User.hasMany(Teacher)
User.hasMany(Student)
I have followed what is mentioned in the Sequelize docs and also other Stack Overflow answers but it just doesnt seem to work.
My database contains two different collections I have "groups" and I have "users". Each group has a field "participants" which is an array that contains either users or guests. Guests unlike users are stored in the group (since they're bound to the specific group).
I use the "participant" schema as an abstraction object between users/guests and the group, this way I can give different users different privileges.
Now to my problem. What I want is the "participant" schema to work for both users and guests which it would if guests would have been its own collection. However, in this case guests belong to the group object and I'm therefore not sure how I'm supposed to reference it. I've tried enum: ["user", "guests"] and enum: ["user", "meetings.guests"] but without any result. I only get the following error:
MissingSchemaError: Schema hasn't been registered for model "guests".. This tells me that I obviously haven't understood how to reference/link subdocuments in the same collection.
Note that I don't want guests to be their own collection
Maybe I can somehow move the "guest" object to "participants.user" but then I would somehow have to tell mongo that it's not an ObjectId anymore but an object?
Group.model.ts
export const ParticipantSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
required: true,
refPath: "participants.userModel"
},
userModel: {
type: String,
required: true,
enum: ["user", "guests"] // How am I supposed to connect the guests as reference? The guests don't have their own collection, they are stored inside the group
},
privilege: {
type: Number,
required: true
}
})
export const GroupSchema = new Schema({
title: {
type: String,
required: true
},
description: {
type: String
},
participants: [ParticipantSchema],
guests: [GuestSchema]
}, {
timestamps: true
})
export default database.model("group", GroupSchema)
User.model.ts
export const UserSchema = new Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true,
}
}, {
timestamps: true
})
export default database.model("user", UserSchema)