MongoError code 66 immutable field in nodeJS - node.js

I was trying to do an update operation. Now I'm getting an immutable error I knew the cause it was updating the key. I wonder because I'm not passing the _id from the API still I can see the _id if I console. I want to remove the _id from my object in order to fix this error. Code below
router.put('/:id', (req, res) => {
//var findid= req.params.id;
if (!ObjectId.isValid(req.params.id))
return res.status(400).send(`No record with given id : ${req.params.id}`);
var alum = new Alumni({
fname: req.body.fname,
lname: req.body.lname,
contact: req.body.contact,
gender: req.body.gender,
dob: req.body.dob,
message: req.body.message,
city: req.body.city,
pincode: req.body.pincode,
state: req.body.state,
district: req.body.district,
password: req.body.password,
email: req.body.email
});
//delete alum['_id'];
Alumni.findByIdAndUpdate(req.params.id, { $set: alum }, { new: true }, (err, doc) => {
if (!err) { res.send(doc); }
else {
console.log(alum);
console.log('Error in Alumni Update :' + JSON.stringify(err, undefined, 2)); }
});
});
How can I resolve this error?

Whenever JSON object is assigned using mongoose model like new Alumni(), by default it assigns _id field which is immutable so you don't need to use model with update object. Simply assign it as given below
var alum = {
fname: req.body.fname,
lname: req.body.lname,
contact: req.body.contact,
gender: req.body.gender,
dob: req.body.dob,
message: req.body.message,
city: req.body.city,
pincode: req.body.pincode,
state: req.body.state,
district: req.body.district,
password: req.body.password,
email: req.body.email
};

Related

mongoose put does not check for required field

I am making nodejs API and I have a user model. Some fields are required. When trigger post it will tell me that some fields required so no save will be done, but when I do it with put it will replace it even if validation is wrong, or even if there is a required field and is missing, but duplicates run good.
this is the model of user
const mongoose = require('mongoose');
const validator = require('validator');
const userSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
firstName: {
type: String,
required: [true, 'the firstName is missing'],
validate: [(val) => validator.isAlpha(val, ['fr-FR']), 'not valid first name'],
},
lastName: {
type: String,
required: [true, 'the lastName is missing'],
validate: [(val) => validator.isAlpha(val, ['fr-FR']), 'not valid last name'],
},
phoneNumber: {
type: String,
required: [true, 'the phoneNumber is missing'],
unique: [true, 'phoneNumber already in use'],
validate: [(val) => validator.isMobilePhone(val,['ar-DZ']), 'not valid phone number'],
},
email : {
type: String,
required: [true, 'the email is missing'],
unique: [true, 'email already in use'],
validate: [validator.isEmail, 'not valid email'],
},
role: {
type : String,
"enum" : ['teacher', 'student'],
required : [true, 'the user `s role is missing'],
}
});
module.exports = mongoose.model('User', userSchema);
this is where I handle put
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const User = require('../../../../models/user');
router.put('/', (req, res) => {
//get the new user object
const userId = req.body.userId;
User.replaceOne({
_id: userId
},
{
_id: userId,
firstName: req.body.firstName,
lastName: req.body.lastName,
phoneNumber: req.body.phoneNumber,
email: req.body.email,
role: req.body.role
})
.exec()
.then(response => {
res.status(200).json(response);
})
.catch(err => console.log(err));
});
module.exports = router;
so I tried to test those, by postman, I wanted from mongoose to do that automatically, I thought about splitting it and redirect it to delete then post, but i will need to do the checking first, or just do the checking manually, and because am using api, I don't want to use the patch method so I don't track the user for what changes he did in the front end.
You can, instead of replaceOne() use updateOne() or findOneAndUpdate() with turned on validators (as they are of by default), like so:
User.updateOne({_id: userId},
{
_id: userId,
firstName: req.body.firstName,
lastName: req.body.lastName,
phoneNumber: req.body.phoneNumber,
email: req.body.email,
role: req.body.role
},
{runValidators: true})
.then(response => {
res.status(200).json(response);
})
.catch(err => console.log(err));
Or you can call the validate() on the new instance of the model and if it is valid continue with update logic, e.g.
let user = new User({_id: userId,
firstName: req.body.firstName,
lastName: req.body.lastName,
phoneNumber: req.body.phoneNumber,
email: req.body.email,
role: req.body.role});
user.validate()
.then(() => {
// update logic
})
.catch((err) => {
// handle error
})
Look for more information on Mongoose validation with update.

Why is the create() function in node js not creating the data in the mongoDB?

I basically wrote a code to check if the data is existing or not in the mongoDB and if it is then I'm trying to create a new document and if it is then I'm basically updating the same document
this is my controller code
Controller.js
try {
console.log(req.body)
let data = await IITSchema.findOne({ Email })
console.log(data)
if (data) {
const updateFormData = await IITSchema.findOneAndUpdate(
{ Email },
{
PhoneNumber,
YearofGrad: YearofGrad,
FullName,
Evidence,
CollegeName: CollegeName,
user: SaveUserData._id,
City: City,
GraduationDegree: GraduationDegree,
Department: Department,
placement_time: placement_time,
targeted_companies: targeted_companies,
interests,
In_what_areas_do_you_need_our_help,
Others,
}
);
return res.status(200).json({ message: "update", data: updateFormData });
} else {
// if (!SaveFormData) {
const newformdata = new IITSchema({
})
const newFormData = await IITSchema.create({
Email,
password: hashedPassword,
PhoneNumber,
YearofGrad: YearofGrad,
FullName,
Evidence,
CollegeName: CollegeName,
// user: user._id,
City: City,
GraduationDegree: GraduationDegree,
Department: Department,
placement_time: placement_time,
targeted_companies: targeted_companies,
interests,
In_what_areas_do_you_need_our_help,
Others,
});
return res.status(200).json({ message: "create", data: newFormData });
}
} catch {
(err) => {
console.log("error from New Step Form", err);
res.json({ error: err });
};
}
this is my Model
const mongoose = require("mongoose");
const IITSchema = new mongoose.Schema({
FullName: String,
Email: String,
interests: { type: [String] },
CollegeName: String,
YearofGrad: String,
password: String,
Evidence: Boolean,
Department: String,
GraduationDegree: String,
In_what_areas_do_you_need_our_help: { type: [String] },
City: String,
placement_time: String,
targeted_companies: String,
PhoneNumber: String,
Others: String,
referral: { type: String, default: null },
});
module.exports = mongoose.model("iitbombay", IITSchema);
and this is the req.body that I'm getting from the front end
{
FullName: 'Mohammed Khan',
Email: 'aven.farhan#gmail.com',
password: 'asdfsadfsd',
Evidence: true,
PhoneNumber: '+919515876470',
CollegeName: ' GURU PRAKASH B.ED. COLLEGE , Kaimur (Bhabua), Bihar',
YearofGrad: 2023,
GraduationDegree: 'Bsc',
Department: 'CSE',
City: 'Adoni',
In_what_areas_do_you_need_our_help: [ 'Complete Placement Preparation' ],
targeted_companies: 'FAANG (Facebook, Amazon, Apple, Netflix and Google)',
placement_time: 'Less than 1 month',
interests: [ 'Data Science / Analytics' ]
}
this is the code that I'm using to send the data to the backend i.e node js and mongodb
await fetch(BASE_URL + "/iitbfform", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(newData),
})
.then((res) => res.json())
.then((data) => {
console.log("Response from firstForm", data);
});
the code is completely fine but the document is not getting saved
it would mean alot if some can point out the error that I'm doing over here

Response is not defined for a mongoose function findOneAndUpdate?

I am updating and returning(new Object) a existing object in the database with mongoose findOneAndUpdate but getting an error
Error
response is not defined
at Function.module.exports.updateProfile ........
In router File
router.post('/edit_profile', (req, res) => {
let updateProfile = new Profile({
name: req.body.name,
email: req.body.email,
username: req.body.username,
gender: req.body.gender,
bio: req.body.bio,
user_id: req.body.user_id
});
console.log(updateProfile); //consoling data Place(1)
Profile.updateProfile(updateProfile.user_id, (err, user) => {
if (err) throw err;
else {
console.log("Update User");
console.log(user);
res.json({
user: user
})
}
})
})
consoled data at Place(1)
{ _id: 5c9cd517b3b7db248c6d7981,
name: 'Shivva',
email: 'ritinbhardwaj933#gmail.com',
username: 'zzz',
gender: 'Male',
bio: 'I am HOwdy Member',
user_id: '5c9cd47bf3d9bb1ea8cbfcbe' }
In profile.js
module.exports.updateProfile = (id, callback) => {
let query = { user_id: id };
console.log(query); //consoling data Place(2)
Profile.findOneAndUpdate(query, { $set: response }, { new: true }, (err, user) => {
if (err) throw err;
else {
callback(null, user);
}
});
}
consoled data at Place(2)
{ user_id: '5c9cd47bf3d9bb1ea8cbfcbe' }
Error
The error i am getting is response is not defined a the Function.module.exports.updateProfile
Error
the accepted solution worked but now it is returning the error
collection.findAndModify is deprecated. Use findOneAndUpdate, findOneAndReplace or findOneAndDelete instead
If you look closely, in this line you have used variable response but never have you initialised it.
Profile.findOneAndUpdate(query, { $set: response }, { new: true }, (err, user) => {
That response word should be replaced with an object with whatever changes you want eg.{ name: 'jason bourne' }
And honestly you don't need to create an instance like what you have done below because you aren't using that anywhere.
let updateProfile = new Profile({
name: req.body.name,
email: req.body.email,
username: req.body.username,
gender: req.body.gender,
bio: req.body.bio,
user_id: req.body.user_id
});

User with favourites and likes system in Mongoose schemas

I want to create a DB with Users which also have a reference to another DB called "Library" which has "favourites" and "likes". I will show the idea here:
User Model
const userSchema = Schema({
username: {type: String, minlength: 4, maxlength: 10, required: true, unique: true},
email: {type: String, required: true, unique: true},
password: {type: String, required: true},
isVerified: { type: Boolean, default: false },
library: {type: Schema.Types.ObjectId, ref: 'Library'}
}, { timestamps: true});
Library Model
const librarySchema = new Schema({
likes: [{
likeId: {type: String},
mediaType: {type: String}
}],
favourites: [{
favId: {type: String},
mediaType: {type: String}
}],
user: {type: Schema.Types.ObjectId, ref: 'User'}
});
Can you please tell me if this is the right way to implement these models or if there is a better way?
At the moment if I try to call
User.findOne({email: 'xxx#xxx.com'}).populate('library').exec(function (err, library)
it doesn't find anything...
Library POST request
router.post('/favourites', passport.authenticate('jwt', {session: false}), function (req, res) {
const favouritesFields = {};
if (req.body.favId) favouritesFields.favId = req.body.favId;
if (req.body.mediaType) favouritesFields.mediaType = req.body.mediaType;
Library.findOne({user: req.user._id}).then(library => {
if (library) {
Library.update({user: req.user._id}, {$push: {favourites: favouritesFields}})
.then(library => res.json(library));
} else {
new Library({user: req.user._id, favourites: favouritesFields}).save().then(library => res.json(library));
}
});
});
User POST request
router.post('/signup', function (req, res) {
const {errors, isValid} = validateSignupInput(req.body);
if (!isValid) {
return res.status(400).json(errors);
}
// Check if email already exists
User.findOne({email: req.body.email}, function (user) {
if (user) {
return res.status(400).json({
title: 'Email already exists'
});
}
});
// Create and save the new user
let user = new User({
username: req.body.username.toLowerCase(),
email: req.body.email.toLowerCase(),
password: bcrypt.hashSync(req.body.password, 10)
});
user.save(function (err, result) {
if (err) {
return res.status(500).json({
title: 'An error occurred during the signup',
error: err
});
}
res.status(201).json({
title: 'User created',
obj: result
});
Your problem is not with the query you're making. there is no foundUser.library because one was never added.
You're adding users to libraries, but you're not adding libraries to your users. if you run the following code in your app:
Library.find({}).populate("user").exec(function(err, foundLibraries){
if (err){
console.log(err);
} else {
console.log(foundLibraries);
}
});
You would see that the libraries have their "user" properties, that when populated contain the entire user document as an object. But, the reason that isn't working for foundUser.library when you query for users is that foundUser.library was never assigned. you know how you're assigning the email, username and password when creating users, you have to do the same for the library property. Or, in your case, since a library is only created after the user, you can just set the value of user.library in the callback of creating/saving the library.

insert embedded document in mongodb using nodejs

I am trying to insert embedded document in MongoDB through nodejs. This is schema of embedded document
var patientSchema = new mongoose.Schema({
status: {type: String},
message:{type: String},
statusCode:{type: Number},
user: [{
pname: {type : String },
email: {type : String },
password: {type : String },
mobile: {type : String},
otp:{type: Number},
age: {type : String }
}]
})
and here is the code of insertion
router.post('/panel/register', function(req, res){
console.log(req.body.mobile_number+req.body.email);
new patient({
status: "ok",
message:"success",
statusCode:"201",
'user.$.pname': req.body.name,
'user.$.password': req.body.password,
'user.$.email': req.body.email,
'user.$.mobile': req.body.mobile_number
}).save(function(err, doc){
if(err) res.json(err);
else {
res.json({"doc ":doc});
}
})
})
but whenever i am trying to insert data using this code it is showing me this error
{
"code": 11000,
"index": 0,
"errmsg": "E11000 duplicate key error index: rhc.patients.$mobile_1 dup key: { : null }",
"op": {
"status": "ok",
"message": "success",
"statusCode": 201,
"_id": "59f38e4d94fff613fc8c4979",
"user": [],
"__v": 0
}
}
As i am understanding this error is because this is not mapping the values of email, mobile inside the user, can someone help to resolve it, i think i am inserting it in wrong way , please help
Edit:
For clarity: the problem wasn't really the syntax, but rather a unique constraint that was removed, without the database being updated. You can read more about that here and here.
Original answer:
You can do it like this:
router.post('/panel/register', function(req, res){
console.log(req.body.mobile_number+req.body.email);
new patient({
status: "ok",
message:"success",
statusCode:"201",
user: [{
pname: req.body.name,
password: req.body.password,
email: req.body.email,
mobile: req.body.mobile_number
}]
}).save(function(err, doc){
if(err) res.json(err);
else {
res.json({"doc ":doc});
}
})
})
This will create a user object in the user array. Are you sure it's supposed to be an array on not just an object? Remove [] from both the model and controller to make it an ordinary object.

Resources