Pass a Button value and Update the database - node.js

Working on a personal project, one of the functions of the project is to update the user status on what event they are participating.
i wanted to submit a value using a button
<form action="/users/fooddrivebanner" method="POST"><button name="fooddrive" type="submit" value="fooddrive" id="fooddrive">Participate</button></form>
then pass the value to my route and save it inside my database
router.post('/fooddrivebanner', (req,res)=>{
const { fooddrive } = req.body;
const _id = ObjectId(req.session.passport.user._id);
User.findOne({ _id: _id }).then((user)=>{
if (!user) {
req.flash("error_msg", "user not found");
res.redirect("/fooddrivebanner");
}
if (typeof eventparticpating !== "undefined") {
user.eventparticpating = 'fooddrive';
}
user.save(function (err, resolve) {
if(err)
console.log('db error', err)
// saved!
});
})
.catch((err) => console.log(err));
Here is the User model
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
},
eventparticpating: {
type: String,
default: 'None At The Moment'
}
});
const User = mongoose.model('User', UserSchema);
module.exports = User;
It showed a console error
TypeError: Cannot set property 'eventparticpating' of null
UPDATE
Edit 1:
I followed Mr Gambino instructions, error Gone yet cannot update the database, how would i be able to adjust and find my user?

Instead of saving within the findOne function,you can do this:
router.post('/fooddrivebanner', async (req,res) => {
const { fooddrive } = req.body;
const _id = ObjectId(req.session.passport.user._id);
await User.findOne({ _id: _id }, (error, user) => {
if (error) {
req.flash("error_msg", "user not found");
res.redirect("/fooddrivebanner");
}
}).updateOne({ eventparticpating: "foodrive" });
});
I hope that answers your question

Related

How to update user lastlogin time in react

i want to display last login time of user in table column after they logged in. i tried with some code in backend with nodejs and mongoose but sure it is not the right way. Can anyone help me how to handle it from backend and FE as well?
Here is Schema of user:
const userSchema = new Schema(
{
name: { type: String },
email: { type: String, unique: true},
password: { type: String },
status: {type: String, enum:["Active", "Blocked"], default:"Active"},
token: { type: String },
lastLogin: { type: Date, default: Date.now()},
},
{ timestamps: true }
);
Route:
userRouter.post("/login", async (req, res, next) => {
try {
const { email, password } = req.body;
if (!(email && password)) res.status(204).send({ msg: "All fields are required!" });
const user = await UsersModel.findOne({ email });
console.log(user);
if (user && (await bcrypt.compare(password, user.password))) {
const accessToken = await JWTAuthenticate(user);
user.token = accessToken;
user.lastLogin = Date.now()
res.status(200).send(user);
} else {
res.status(404).send({ msg: "User with this email not found!" });
}
UsersModel.findOneAndUpdate({lastLogin: Date.now()}, (err, data) => {
if(err) console.log(err);
else console.log("Successfully updated the lastLogin", data);
})
} catch (error) {
next(error);
}
});
You just have to call await user.save() after setting lastLogin (and remove findOneAndUpdate call)
or
actually query for the user in your findOneAndUpdate call. Currently you are querying for a 'lastLogin' field with the value now() which will never match. Adjust this call as following:
UsersModel.findByIdAndUpdate(user._id, {lastLogin: Date.now()}, (err, data) => {
if(err) console.log(err);
else console.log("Successfully updated the lastLogin", data);
})
Just a hint: JWTs are used for storing the session state on client side. You don't need to actually store these Tokens in your database. You just have to validate it on incoming request.

Im trying to update a users information using MongoDB and JWT

when I use this code to try and update the user it appears as a server error. Im using JWT and mongodb but am unsure if im pulling the token or the id to update the users information. Below my controller code is attached and my schema.
const updateUser = async (req, res) => {
try {
const user = await User.findByIdAndUpdate(req.user.id)
if(!user) return res.status(400).send({ error: 'User not found'})
Object.assign(user, req.body);
user.save()
res.send({ data: user})
} catch (error) {
res.status(500).send({error: 'Server Error'})
}
}
const mongoose = require('mongoose');
let userSchema = new mongoose.Schema({
name: { type: String, required: true},
email: { type: String, required: true, unique: true},
password: { type: String, required: true},
date: { type: Date, default: Date.now}
})
module.exports = mongoose.model('user', userSchema)
Updated update function but i appear to have an error
const updateUser = async (req, res) => {
try {
const updatedUser = await User.findByIdAndUpdate(req.params.id,req.body)
if(!updatedUser) return res.status(400).send('User cannot be updated!')
res.json(updatedUser)
} catch (error) {
res.status(500).send({error: 'Server Error'})
}
}
Try this :
//update user by id
exports.updateUser = async (req, res) => {
try {
const updatedUser = await
<--req.params.id is the user.id and req.body contains the requested fields to update -->
User.findByIdAndUpdate(req.params.id,req.body)
res.json(updatedUser);
}
catch (err) {
console.log(err);
res.status(500).json({ message: 'Internal server error' });
}
}

mongoose.updateOne() always updating the first document

I'm making a command for a discord bot in which I want to edit user's info in document. The command looks like this !edit #tag email language this works however it doesnt matter who I ping it will always change the first document in MongoDB.
let user = message.mentions.users.first()
Data.findOne({
userID: user.id,
}, (err, data) => {
if (err) return console.log(err);
if (!data) {
return message.reply("That user isn't in list")
} else {
Data.updateOne({
language: args[2],
email: args[1]
}, (err) => {
if (err) throw err;
let embed = new Discord.MessageEmbed()
.addField("Name", data.name);
message.channel.send(embed)
})
}
Data.js
const mongoose = require("mongoose");
const dataSchema = mongoose.Schema({
name: String,
language: String,
email: String,
userID: String,
lb: String,
usage: Number
})
module.exports = mongoose.model(`Data`, dataSchema)
This is how my documents look like
May you should try this
Data.findOneAndUpdate({ userID: user.id },
{ $set: { language: args[2], email: args[1] } },
{ new: true }).exec((err, data) => {
//further response with updated data
});

find an id in embedded document node mongoose

I have a model of courses with the following structure:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const user_shortid = require('shortid');
// Create Course schema
const CourseSchema = new Schema({
courseDetail: {
type: String
},
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
enrolledUsers: [{
type: Schema.Types.ObjectId,
ref: 'users'
}],
currentStatus: {
type: String,
default: 'Planned'
}
});
mongoose.model('courses', CourseSchema);
I have created a post request for adding a signed in user to the array of enrolledUsers, the problem is, I want to check first if the req.user.id exists in the enrolledUsers array. Following is my post request:
router.post('/joincourse', [ensureAuthenticated], (req, res) => {
Course.findByIdAndUpdate({ _id: req.body.coursecode },
{ $push: { enrolledUsers: req.user.id } },
{ safe: true, upsert: true },
function (err, doc) {
if (err) {
req.flash('error_msg', 'Could not enroll in the course');
res.redirect('/dashboard');
} else {
req.flash('success_msg', 'You are now enrolled in the course');
res.redirect('/dashboard');
}
}
);
});
Right now the behavior is that a user can enroll again and again in the same course.
Is there some way I can check for the req.user.id in the enrolledUsers array before it is added?
you can do find the user first by using find() and then if a user exists, update it , else
give an error like this
router.post('/joincourse', [ensureAuthenticated], (req, res) => {
Course.findById({ _id: req.body.coursecode },
function (err, doc) {
if (err) {
req.flash('error_msg', 'Could not enroll in the course');
res.redirect('/dashboard');
} else {
if(doc){
if(!doc.enrolledUsers.includes(req.user.id)){ // here is the checking
doc.enrolledUsers.push(req.user.id);
doc.save();
req.flash('success_msg', 'You are now enrolled in the course');
res.redirect('/dashboard');
}
}else{
// show error msg
}
}
}
);
});

How do you save to three collections at once?

I'm building my first mean stack app. It's a review site that contains three models: User, Review, and Company.
When I make a review, I want the new review to be saved to the 'review' collection, and for that review to be connected by reference to the company being reviewed and the user who wrote the review. I also want the user to hold a reference to the review, and the company to hold a reference to all the reviews it has. Here are my models:
Review
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const reviewSchema = new Schema ({
companyName: String,
companyId: { type: Schema.Types.ObjectId, ref: 'Company'},
starRating: Number,
subject: String,
commentBody: String,
createdBy: { type: Schema.Types.ObjectId, ref: 'User'},
});
const Review = mongoose.model("Review", reviewSchema);
module.exports = Review;
Company
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const companySchema = new Schema ({
companyName: String,
about: String,
basedIn: String,
materialOrigins: [String],
productRange: [String],
category: String,
reviews: [ {type: Schema.Types.ObjectId, ref: 'Review'} ],
socialRating: Number,
environmentalRating: Number,
priceRange: Number
});
const Company = mongoose.model("Company", companySchema);
module.exports = Company;
User
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema ({
email: String,
firstName: String,
lastName: String,
password: String,
image: Object,
aboutText: String,
reviews: [ { type: Schema.Types.ObjectId, ref: "Review" } ]
// comments: { type: Schema.Types.ObjectId, ref: 'Comment' }
});
const User = mongoose.model("User", userSchema);
module.exports = User;
This is my current route, which currently saves the review to the collection and attaches the user. However, the user doesn't get the review.
route
router.post('/:category/:company', (req, res) => {
var subject = req.body.subject;
var commentBody = req.body.commentBody;
var starRating = req.body.starRating;
var userId = req.body.userId;
if(!subject || !commentBody || !starRating) {
res.status(400).json({ message: "Subject, comment body, and star rating are required." });
return;
}
var newReview = Review({
starRating,
subject,
commentBody,
userId
});
User.findById(userId, {
}, (err, user) => {
if (err) {
return res.send(err);
} else {
console.log("checking out user in route", user);
user.reviews.push(newReview);
user.save();
newReview.save((err, review) => {
if (err) {
return res.status(400).json({ message: err });
} else {
res.status(200).json({ message: 'Review saved', review });
}
});
}
});
I haven't tried adding the company in because I'm trying to do one thing at a time. I've been looking at 'populate', but all of the documentation seems to only use two models at once. Is it possible to do three at once? Or am I overcomplicating this?
Apologies if this is all overcomplicated. I'm fairly new to MongoDB and MEAN stack in general. Thanks for your help.
Ok, I did it, for any people landing on this page wondering the same thing in the future.
Here's my route:
router.post('/:category/:company', (req, res, next) => {
var companyName;
var companyId;
var subject = req.body.subject;
var commentBody = req.body.commentBody;
var starRating = req.body.starRating;
var createdBy = req.body.createdBy;
if(!subject || !commentBody || !starRating) {
res.status(400).json({ message: "Subject, comment body, and star rating are required." });
return;
}
var newReview = Review({
starRating,
subject,
commentBody,
createdBy
});
//I need the companyId and companyInfo for later use in my review save. I'm calling the company with the name I have from my params, and setting the id and name with the received data from Mongo.
Company.findOne({"companyName": req.params.company}, (err, company) => {
if (err) {
return res.status(400).json({ message: err });
} else {
this.companyName = company.companyName;
this.companyId = company.id;
}
});
newReview.save((err, review) => {
//Push the review id to the user
if (err) {
return res.status(400).json({ message: err });
} else { User.findByIdAndUpdate({_id: createdBy },{$push: {reviews: review.id} }, (err) => {
if (err) {
console.log("There was an error pushing review to user");
next(err);
//Push the review id to the company
} else { Company.findOneAndUpdate({ "companyName": req.params.company}, {$push: {reviews: review.id}}, (err, company) => {
if (err) {
console.log("There was an error pushing review to company");
next(err);
} else {
//Updates the review by setting companyId and companyName properties to review for Mongo
Review.update({_id: review.id}, {$set: {companyId: this.companyId, companyName: this.companyName}}, (err, changes) => {
if(err) {
return res.status(400).json({message : err});
} else {
console.log("updating review successfully with company info", changes);
}
});
console.log ("Review successfully saved");
res.json({
review: review,
});
}
});
}
});
}
});
});
If anyone has feedback on how this could be done better/more efficiently, let me know. Cheers.

Resources