I am a beginner in Node Js /Express and am currently trying to design a simple chess forum. I am having great difficulty creating the CRUD functions for the different entities. The 3 entities are: User, Message and Colour.
Their relationship to each other is User.OneToMany(Message) and Colour.OneToMany(Message).I use Mongoose.
user.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var user = new Schema({
name: {
type: String
},
email: {
type: String
},
password: {
type: String
}
});
const UserDB= mongoose.model('user', user);
module.exports = UserDB;
message.js
const mongoose = require('mongoose');
const Schema= mongoose.Schema;
var message = new Schema({
titel: {
type: String
},
message: {
type: String
},
user: {
type: Schema.Types.ObjectId,
required: true,
ref: 'User'
},
color: {
type: Schema.Types.ObjectId,
required: true,
ref: 'color'
}
});
const MessageDB= mongoose.model('message', message);
module.exports=MessageDB
color.js
const mongoose = require('mongoose');
const Schema= mongoose.Schema;
var color = new Schema({
color: {
type: String
}
});
const ColorDB=mongoose.model('Color', color);
module.exports=ColorDB
I have implemented all the CRUD functions for the user.
controller.js
var UserDB = require('../model/user');
//CRUD for User
//(c)reate new User
exports.create=(req,res)=>{
//validate
if(!req.body){
res.status(400).send({message:'Empty'});
return;
}
//hash password
//const hashedPassword= bcrypt.hashSync(req.body.password,salt)
//
//new user
const user = new UserDB({
name: req.body.name,
email: req.body.email,
password: req.body.password
})
//save database
user
.save(user)
.then(data => {
res.redirect('/signup')
})
.catch(err =>{
res.status(500).send({
message: err.message || "Mars Attacks !"
})
});
}
//(r)ead User
exports.find=(req,res)=>{
//find by email (login)
if (req.query.email){
const email=req.query.email;
const password=req.query.password;
UserDB.findOne({email: email, password:password})
.then(data=>{
if(!data){
res.status(404).send({message: 'Not found user with email' +email})
} else {
res.redirect('/forum')
}
})
.catch(err=>{
res.status(500).send({message: 'Error reading user with email' +email})
})
}
//find by id
if(req.query.id){
const id=req.query.id;
UserDB.findById(id)
.then(data=>{
if(!data){
res.status(404).send({message: 'Not found user with id' +id})
} else{
res.send(data)
}
})
.catch(err=>{
res.status(500).send({message: 'Error reading user with id' +id })
})
}else{
UserDB.find()
.then(user =>{
res.send(user)
})
.catch(err =>{
res.status(500).send({
message: err.message || 'Ack! Ack!' })
})
}
}
//(u)pdate User
exports.update=(req,res)=>{
if(!req.body){
return res
.status(400)
.send({message: 'Data to update can not be empty.'})
}
const id= req.params.id;
UserDB.findByIdAndUpdate(id,req.body,{useFindAndModify: false})
.then(data=>{
if(!data){
res.status(404).send({message: `Cannot Update user with ${id}`})
}else{
res.send(data)
}
})
.catch(err=>{
res.status(500).send({message: 'Laserbeam !'})
})
}
//(d)elete User
exports.delete=(req,res)=>{
const id = req.params.id;
UserDB.findByIdAndDelete(id)
.then(data=> {
if(!data){
res.status(404).send({message: `Cannot Delete ${id}`})
}else{
res.send({
message: 'Gone!'
})
}
})
.catch(err=>{
res.status(500).send({
message:'Ack ! Could not delete User with id=' + id
});
});
}
My router looks like this:
router.js
const express = require('express');
const route = express.Router();
const controller = require ('../controller/controller');
//API
route.post('/api/users',controller.create);
route.get('/api/users',controller.find);
route.put('/api/users/:id',controller.update);
route.delete('/api/users/:id',controller.delete);
module.exports=route;
I tried to transfer the concept of the controller to the other 2 entities (message,colour). Unfortunately in vain. What are the crud functions for the other two entities ?
first you need to save the user ID as a session or via token. I would suggest look into passport.js for more information on this one.
After you have set the session.. you can access the userID in req.user.
You can now easily create a CRUD like this as an example - create only
// route
route.post('/api/message',messageController.create);
// create controller
// post data json
// {
// color:'color_ID'
// }
function create(req, res){
const message = {
titel:'this is a title',
message:'this is a message',
user: req.user,
color: req.body.color
};
await Message.create(message);
res.json({mesage:'Message Created'})
}
Related
I'm trying to be able to delete a user if they choose to delete their account. I'm not sure how it's properly done. Here's the code for the delete function. I've looked at other StackOverflow solutions but I haven't been able to grasp the concept just yet. can anyone help?
const { validationResult } = require('express-validator')
const User = require('../modelSchema/User')
const mongo = require('mongodb')
const signUp = (req, res) => {
const errors = validationResult(req)
if(!errors.isEmpty()) return res.status(400).json({ errors: errors.array()})
//new instance of user
const user = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password })
//save the user
user.save()
.then(data => {
res.json(data)
res.send('User added successfully!')
console.log(data)
})
.catch(err => {
res.status(400).json(err)
})
}
const deleteUser = (req, res) => {
let id = req.params.id;
User.get().createCollection('user', function ( col) {
col.deleteOne({_id: new mongo.ObjectId(id)});
});
res.json({ success: id })
res.send('User Deleted Successfully!')
.catch(err => {
res.status(400).json(err)
})
}
module.exports = { signUp, deleteUser }
here are the routes that I'm using
const express = require('express');
const { check } = require('express-validator')
const { signUp, deleteUser } = require('../controllers/users');
const router = express.Router();
router.post('/signup', [
check('name', 'Please Enter your Name').not().isEmpty(),
check('email', 'Please Enter your Email').isEmail(),
check('password', 'Please Enter your Password').isLength({ minLength: 6})
], signUp)
router.delete('/delete/:id', deleteUser)
module.exports = router;
and here's my schema
const mongoose = require('mongoose');
let 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}
})
module.exports = mongoose.model('user', userSchema)
Update your delete function as below
const deleteUser = async (req, res) => {
const { id } = req.params;
const user = await User.findByIdAndDelete(id);
if (!user) {
return res.status(400).json("User not found");
}
res.status(200).json("User deleted successfully");
};
findByIdAndDelete takes an ObjectId of a user to be deleted. If the user exist, it'll delete the user and return user document, else return null;
I stuck with a problem, when I hit my route addBook then getting an error like book is not defined don't know where I am please try to fix my code. if you have any query on my code please let me know.
route.js
This is the route.js file where I wrote my all logics
const express = require("express");
const router = express.Router();
const Publisher = require('../model/Categary');
const Book = require('../model/Product');
// const {addCatogary} = require('../controllers/Product');
// router.get('/addcatogary',addCatogary);
router.post("/addPublisher", async (req, res) => {
try {
//validate req.body data before saving
const publisher = new Publisher(req.body);
await publisher.save();
res.status(201).json({ success: true, data: publisher });
console.log(publisher);
} catch (err) {
res.status(400).json({ success: false, message: err.message });
}
console.log(err);
});
router.post("/addBook", async (req, res) => {
try {
//validate data as required
const book = new Book(req.body);
// book.publisher = publisher._id; <=== Assign user id from signed in publisher to publisher key
await book.save();
const publisher = await Publisher.findById({ _id: book.publisher });
publisher.publishedBooks.push(book);
await publisher.save();
//return new book object, after saving it to Publisher
res.status(200).json({ success: true, data: book });
} catch (err) {
res.status(400).json({ success: false, message: err.message });
}
console.log(book);
});
router.get("/publishers", async (req, res) => {
try {
const data = await Publisher.find().populate({
path: "booksPublished",
select: "name publishYear author",
});
res.status(200).json({ success: true, data });
} catch (err) {
res.status(400).json({ success: false, message: err.message });
}
console.log(data)
});
module.exports = router;
Product.js
const mongoose= require('mongoose');
const {Schema} = require('mongoose');
const bookSchema = new Schema({
name: String,
publishYear: Number,
author: String,
publisher: {
type: Schema.Types.ObjectId,
ref: 'Publisher',
required: true
}
},
{timestamps: true});
module.exports = mongoose.model('Book', bookSchema);
Catogary.js
This is the Catogary model.
const mongoose = require('mongoose');
const {Schema} = require('mongoose');
const publisherSchema = new Schema({
name: String,
location: String
},
{timestamps: true}
);
publisherSchema.virtual('booksPublished', {
ref: 'Book', //The Model to use
localField: '_id', //Find in Model, where localField
foreignField: 'publisher', // is equal to foreignField
});
// Set Object and Json property to true. Default is set to false
publisherSchema.set('toObject', { virtuals: true });
publisherSchema.set('toJSON', { virtuals: true });
module.exports = mongoose.model('Publisher', publisherSchema);
router.post("/addBook", async (req, res) => {
try {
//validate data as required
const book = new Book(req.body);
// book.publisher = publisher._id; <=== Assign user id from signed in publisher to publisher key
await book.save();
const publisher = await Publisher.findById({ _id: book.publisher });
publisher.publishedBooks.push(book);
await publisher.save();
//return new book object, after saving it to Publisher
res.status(200).json({ success: true, data: book });
} catch (err) {
res.status(400).json({ success: false, message: err.message });
}
console.log(book);
});
hey brother!
you have written a nice code but you have made a small mistake after catch block you are logging book which is defined inside try block and that book variable can not be accessed outside of that box because its local variable and can be only used inside try block
if you wanted to used that variable outside of try{} catch(){} block defined it with var
just check below link
geeksforgeeks.org/global-and-local-variables-in-javascript
happy hacking :)
I have this collection Cart (cart schema) to delete and it is referenced with 2 other schemes, Meal and Customer (owner user, its schema is: User Schema).
How can I delete the cart by passing as req.params.id the user's id from the HTTP request?
Cart Schema
const mongoose = require('mongoose');
const idValidator = require('mongoose-id-validator');
const Schema = mongoose.Schema;
const cartItemSchema = new Schema ({
quantity: { type: Number, required: true },
itemId: { type: mongoose.Types.ObjectId, required: true, ref: 'Meal' }
});
const cartSchema = new Schema ({
cartItems : [
cartItemSchema
],
customer: { type: mongoose.Types.ObjectId, required: true, ref: 'User'}
});
cartSchema.plugin(idValidator);
module.exports = mongoose.model('Cart', cartSchema);
I created a function to delete the document, but it doesn't work, it returns the message: 'Deleted cart.', but isn't true, the document remains in collection.
const deleteCartByUserId = async (req, res, next) => {
const userId = req.params.uid;
let cart;
try {
cart = await Cart.find({ customer: userId });
} catch(err) {
const error = new HttpError('Something went wrong, could not delete cart.', 500);
return next(error);
}
if(!cart) {
const error = new HttpError('Could not find cart for this user id.', 404);
return next(error);
}
try {
Cart.deleteOne({ customer: userId });
} catch(err) {
console.log(err);
const error = new HttpError('Something went wrong, could not delete cart.', 500);
return next(error);
}
res.status(200).json({ message: 'Deleted cart.' });
};
So the porblem was that you missed an await before delete one function call.
Also I've changed some of youre code to make it cleaner:
const functionHandler = fn =>
(req, res, next) =>
Promise
.resolve(fn(req, res, next))
.catch(next);
const deleteCartByUserId = functionHandler(async (req, res) => {
const { params: { uid: userId } } = req;
const cart = await Cart.findOneAndDelete({ customer: userId })
if(!cart) {
throw new HttpError('Could not find cart for this user id.', 404);
}
res.status(200).json({ message: 'Deleted cart.' });
});
In your error handler middleware you can check for error type and if it's not HttpError use internal server error.
I have 3 routes in my code , for Users, for Products and For Orders.
I use jwt and generate tokens for users, and I want to assign orders to token Owners.
Here's my Order Model :
var mongoose = require('mongoose');
var orderSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId ,
product: {type: mongoose.Schema.Types.ObjectId, ref: 'Product'},
quantity: {type: Number , default: 1},
user_name: String
});
module.exports = mongoose.model('Order', orderSchema);
And here's my middleware to check Authenticate (It's imported as checkAuth) :
module.exports = (req,res,next) => {
try {
var decoded = jwt.verify(req.headers.token, secretjwt);
req.userData = decoded;
next();
} catch (error) {
return res.status(401).json({
'error': 'Auth Failed',
'details': error.message
});
}
Here's my post api for adding orders, What Should I write as user_name to assign it to the user (I don't want to get username as a body parameter)?
router.post('/newOrder', checkAuth, (req,res,next) => {
var order = new Order({
quantity: req.body.quantity,
product: req.body.productId,
user_name: // WHAT SHOULD IT BE?
});
order.save()
.then(result => {
res.status(200).json(result);
})
.catch(err => {
res.json(200);
});
});
Thanks in advance!
Instead of
req.userData = decoded
put
req.body.userData = decoded
And put user_name: req.body.userData in following snip
router.post('/newOrder', checkAuth, (req,res,next) => {
var order = new Order({
quantity: req.body.quantity,
product: req.body.productId,
user_name: // WHAT SHOULD IT BE?
});
order.save()
.then(result => {
res.status(200).json(result);
})
.catch(err => {
res.json(200);
});
});
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.