Duplicate key error when performing update Express Mongoose - javascript

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.

Related

Express - Mongoose - How to add user data to POST request when submitting a form?

I'm new to Mongoose and NodeJS and I'm building a ticket management system where logged in users can fill up a form to create a ticket. It has two fields (title and description) but when submitting it, I'd like to also add some user's data to the form data object.
On the front end I'm using React with Formik to handle the form.
My user data object is stored in local storage using JWT.
Here are my current models for the ticket and for the user:
//ticket.model.js
module.exports = (mongoose) => {
const Ticket = mongoose.model(
'ticket',
mongoose.Schema(
{
title: String,
description: String,
},
{ timestamps: true }
)
);
return Ticket;
};
//user.model.js
const User = mongoose.model(
'User',
new mongoose.Schema({
firstName: String,
lastName: String,
email: String,
password: String,
roles: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Role',
},
],
})
);
module.exports = User;
Here is the Formik function:
const formik = useFormik({
initialValues: {
title: '',
description: '',
},
validationSchema,
validateOnBlur: false,
validateOnChange: false,
onSubmit: (data) => {
TicketService.create(data).then(() => {
navigate('/home');
window.location.reload();
});
},
});
Ideally, when the ticket is being created I'd like to query Mongoose with user's ObjectId to retrieve his firstName and lastName. If it's too complicated I don't mind just adding the user's names to the form data using JSON.parse(localStorage.getItem('user')). Or if you have better practices, please let me know.
Thank you!
Never mind, my formik object was actually missing the user element (see below).
const formik = useFormik({
initialValues: {
title: '',
description: '',
authorId: JSON.parse(localStorage.getItem('user')).id,
authorName: `${JSON.parse(localStorage.getItem('user')).firstName} ${
JSON.parse(localStorage.getItem('user')).lastName
}`,
},
validationSchema,
validateOnBlur: false,
validateOnChange: false,
onSubmit: (data) => {
console.log(data);
TicketService.create(data).then(() => {
navigate('/home');
window.location.reload();
});
},
});
From there I just updated my model and controller accordingly:
module.exports = (mongoose) => {
const Ticket = mongoose.model(
'ticket',
mongoose.Schema(
{
title: String,
description: String,
authorId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
authorName: String,
},
{ timestamps: true }
)
);
return Ticket;
};

Add a new field to every document from my mongo DB collection via mongoose

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.

Working with embeeded documents and multiple schemas in one collection, mongoose

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?

Sequelize: Create with Association not working

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.

How do I find if an Id is present in the array of team members (which stores user ids)?

I have this model of workspace schema in my node js project(model is displayed below)
After the user logs into my application I want to display the information of a workspace only if it is created by him or he is a team member of that workspace
I am able to find the workspaces created by the user by the following query
Workspace.find({creator:req.user._id},function(err,workspaces){
res.render('home',{
wokspacses:workspaces
});
});
similarly, I also want the workspaces in which the user is the team member
Workspace.find({creator:req.user._id},function(err,workspaces){
Workspace.find({team_member:"WHAT SHOULD I WRITE HERE"},function(err,workspaces2){
res.render('home',{
wokspacses:workspaces
wokspacses2:workspaces2
});
});
Since team_members is an array simply passing the user id is not yielding the result and workspaces2 remains empty
Thank you for your time !!
const mongoose = require('mongoose');
const workspaceSchema = mongoose.Schema({
name:{
type:String,
required:true
},
date: {
type: Date,
required: true
},
creator:{
type: Object,
ref: 'User',
required: true
},
team_member: [{ type: Object, ref: 'User' }]
});
module.exports = mongoose.model('Workspace',workspaceSchema);
Use the $in Operator.
const mongoose = require("mongoose")
const Schema = mongoose.Schema
mongoose.connect('mongodb://localhost/stackoverflow', {useNewUrlParser: true});
const workspaceSchema = new Schema({
name:{
type:String,
required:true
},
date: {
type: Date,
required: true
},
creator:{
type: Object,
ref: 'User',
required: true
},
team_member: [{ type: Object, ref: 'User' }]
});
const WorkspaceModel = mongoose.model('Workspace',workspaceSchema);
const sessionUserId = "5d330f3de87ec83f95504c44" //i.e. req.user._id;
WorkspaceModel.find({
$or:[
{ creator: sessionUserId },
{
team_member: {
$in: [sessionUserId]
}
}
]
}).exec((err, result) => {
console.log("result", result)
})

Categories

Resources