UnhandledPromiseRejectionWarning: ReferenceError: book is not defined - node.js

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 :)

Related

Mongoose is not saving array in the mongo db

tasks array is not getting saving the data base when I'm sending data from postman.
I'm sending data by hitting postman but it is only saying the title field values but not tasks array values like below
{
"title": "my first test59",
"tasks": ["task1","task2","task3"]
}
Since I'm using create method save is not needed that's why I'm not using it in my model. I'm not getting it why it is not working out.
My model:
const mongoose = require("mongoose");
const schema = mongoose.Schema;
const toDoSchema = new schema({
title:{
type: String,
require: [true, "title is required"],
trim: true
},
tasks:{
type:[String],
trim: true
}
});
const toDoModel = mongoose.model("toDo", toDoSchema);
module.exports = toDoModel;
//importing model
const toDoModel = require('../models/ToDoModel');
//creating controller function
const createToDoController = async (req,res)=>{
try{
const {title,toDoTasks} = req.body;
if(!title) //input validation
{
throw new Error("Please provide the title");
}
const newToDo = await toDoModel.create({ title, toDoTasks });
res.status(201).json({
success: true,
message: "User Created Successfully",
newToDo,
});
}
catch(err){
res.status(500).json({
success: false,
message: "Unable to perform create operation",
error: err
})
res.send(err.message);
}
}
module.exports = createToDoController;
controller.js
//importing model
const toDoModel = require('../models/ToDoModel');
//creating controller function
const createToDoController = async (req,res)=>{
try{
const {title,toDoTasks} = req.body;
if(!title) //input validation
{
throw new Error("Please provide the title");
}
const newToDo = await toDoModel.create({ title, toDoTasks });
res.status(201).json({
success: true,
message: "User Created Successfully",
newToDo,
});
}
catch(err){
res.status(500).json({
success: false,
message: "Unable to perform create operation",
error: err
})
res.send(err.message);
}
}
module.exports = createToDoController;
Change "tasks" instead of "toDoTasks" in request body. It will work.
const {title,tasks} = req.body;

MERN STACK image upload to MongoDB

hi can someone help me out im developing a MERN STACK APP with aws s3 i have 2 schema models one for user and one for images, im making a ref to the user inside my image schema, im successfully adding to MongoDB atlas the user with image, my issue is i want the user to be able to add the image in the existing array not a new one like its doing now and also how can i get all the data for the user thats logged in on the front end as off now im getting the same images for all users who log in.
-image schema-
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const imageSchema = new Schema(
{
user: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
},
image: {
type: [String],
default: "",
required: true,
},
},
{
timestamps: true,
}
);
module.exports = mongoose.model("PostImage", imageSchema);
-upload image-
const imageUploadS3 = (req, res, next) => {
const uploadSingle = upload("mern-stack-imageupload-insta").single("image");
uploadSingle(req, res, async (err) => {
if (err)
return res.status(400).json({ success: false, message: err.message });
console.log(req.file);
const imgDB = await PostImage.create({
user: req.userId,
image: req.file.location,
});
try {
await imgDB.save();
res.status(200).json({
success: true,
message: "image uploaded",
image: imgDB,
data: req.file.location,
});
} catch (error) {
res.status(500).json({ message: error.message });
}
});
};
getImage route
const getImages = async (req, res) => {
const { id } = req.userId;
try {
const image = await PostImage.findById(id);
if (!image) {
return res.status(404).json({ message: "Image not found" });
}
res.status(200).json(image);
} catch (error) {
res.status(409).json({ message: error.message });
}
};

How to Delete document and sub documents referenced from others collections - MongoDB Mongoose

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.

Mongoose one-to-many not working (Nodejs)

I have created 2 Users(Admin and Users) and also i have created many ToDos for a User but here my Todo array is empty in my User Schema. Unable to understand why todo task are not assigned to the User Schema.
UserSchema
var userSchema = new Schema({
name: {
type: String,
required: true,
maxlength: 30,
trim: true
},
role: {
type: Number,
default: 0
},
todos: [{
type: Schema.Types.ObjectId,
ref:"Todo"
}]
});
module.exports = mongoose.model("User", userSchema)
Todo Schema
let Todo = new Schema({
todo_heading: {
type: String
},
todo_desc: {
type: String
},
todo_priority: {
type: String
},
todo_completed: {
type: Boolean
},
user: {
type: Schema.Types.ObjectId,
ref:"User"
}
})
module.exports = mongoose.model('Todo', Todo);
here are my routes
User Route
router.get("/user/:userId/todos", isSignedIn, isAuthenticated, getToDos)
Todo Route
router.get("/", getTodos)
router.get("/:id", getUsertodos);
router.post("/user/:userId/add", addUsertodos);
User Controllers
exports.getToDos = (req, res) => {
User.find({ _id: req.params._id })
.populate("todos")
.exec((err, toDo) => {
if (err) {
res.json(err)
}
res.json(toDo)
})
}
ToDo Controllers
exports.addUsertodos = (req, res) => {
let todo = new Todo(req.body)
todo.save((err, todo) => {
if (err) {
return res.status(400).json({
error: "not saved"
})
}
else {
return res.json(todo)
}
})
}
it should work as expected if you add the objectId of newly created todo to the todos property when you create a user.
//routers/todo.js
var express = require('express');
var router = express.Router();
const Todo = require('../models/Todo');
const User = require('../models/User');
/* GET home page. */
router.get('/', async function (req, res) {
let todos = await Todo.find();
res.json({
todos
});
});
router.post('/todos', async function (req, res) {
//add todos
let {
todo_desc,
todo_heading,
todo_priority,
todo_completed
} = req.body;
try {
//NOTE: for simplicity assigning first user but you can grab it from the params
let user = await User.findOne();
let todo = await Todo.create({
todo_desc,
todo_completed,
todo_priority,
todo_heading,
user: user._id
})
res.json({
message: 'todo created successfully',
todo
});
} catch (err) {
return res.status(500).json({
message: 'Unable to create a todo',
err: JSON.stringify(err)
})
}
});
module.exports = router;
Here is the user route where post route get the string id of created ID and converts it to ObjectId(), assign it to the todos.
var express = require('express');
var router = express.Router();
let _ = require('lodash');
var mongoose = require('mongoose');
const User = require('../models/User');
/* GET users listing. */
router.post("/", async function (req, res) {
let {
name,
todos
} = req.body;
try {
let user = new User();
user.name = name;
let objectIds = todos.split(',').map(id => mongoose.Types.ObjectId(id));
user.todos.push(...objectIds)
await user.save()
console.log("user: ", JSON.stringify(user));
if (_.isEmpty(user)) {
res.status(500).json({
message: 'unable to create user'
})
}
res.json(user);
} catch (err) {
res.status(500).json({
message: 'unable to create user',
err: JSON.stringify(err)
})
}
});
router.get("/", async function (req, res) {
try {
let user = await User.find().populate('todos');
console.log("user: ", JSON.stringify(user));
if (_.isEmpty(user)) {
res.status(500).json({
message: 'unable to find user'
})
}
res.json(user);
} catch (err) {
res.status(500).json({
message: 'unable to find user',
err: JSON.stringify(err)
})
}
});
module.exports = router;
Check out the attached screenshot, the user record now contains the todos assigned to it.
If you want checkout the working code, please visit this repo that i created!!.
Hope this help.Cheers!!

How can I populate an existing Mongo Document when creating another?

I am using mongoose and express to build an API for storing technology work tickets. I have a field in my Ticket model that references a User id and an array field in my User model that references all the Tickets (by ID) that are owned by that user.
When I create a new Ticket (using HTTP post method), I want my database to automatically add that ticket's id to the tickets field of its assigned user (like a SQL Join). However, I can't get it to work.
I've tried updating my user model inside the /tickets POST request in my router, but can't wrap my head around how to actually make it work.
Here is my code:
// Ticket Model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Promise = require('bluebird');
const ObjectId = mongoose.Schema.Types.ObjectId;
const User = require('./user');
Promise.promisifyAll(mongoose);
const TicketSchema = new Schema({
open: {type: Date, required: true},
close: Date,
description: {type: String, required: true},
done: Boolean,
status: String,
repairType: {type: String, required: true},
ticketOwner: {type: ObjectId, ref: 'User', required: true}
});
const Ticket = mongoose.model('Ticket', TicketSchema, 'tickets');
module.exports = Ticket;
// User Model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Promise = require('bluebird');
const ObjectId = mongoose.Schema.Types.ObjectId;
const Ticket = require('./ticket');
Promise.promisifyAll(mongoose);
const UserSchema = new Schema({
firstName: {type: String, required: true},
lastName: {type: String, required: true},
email: {type: String, required: true},
tickets: [{type: ObjectId, ref: 'Ticket'}]
});
const User = mongoose.model('User', UserSchema, 'users');
module.exports = User;
// Tickets Route
const express = require('express');
const router = express.Router();
const Ticket = require('../models/ticket');
router.route('/')
// READ all tickets.
.get(function(req, res, next) {
Ticket.findAsync({})
.then(function(tickets) {
res.json(tickets);
})
.catch(next)
.error(console.error);
})
// CREATE new ticket.
.post(function(req, res, next) {
let ticket = new Ticket();
let prop;
for (prop in req.body) {
ticket[prop] = req.body[prop];
}
ticket.saveAsync()
.then(function(ticket) {
console.log('success');
res.json({'status': 'success', 'ticket': ticket});
})
.catch(function(e) {
console.log('fail');
res.json({'status': 'error', 'error': e});
})
.error(console.error);
});
router.route('/:id')
// READ a single Ticket by ID
.get(function(req, res, next) {
Ticket.findOne({_id: req.params.id}, {})
.populate('ticketOwner')
.exec(function (e, ticket) {
if (e) return console.error(e);
res.json(ticket);
})
})
// UPDATE a Ticket
.put(function(req, res, next) {
let ticket = {};
let prop;
for (prop in req.body) {
ticket[prop] = req.body[prop];
}
Ticket.updateAsync({_id: req.params.id}, ticket)
.then(function(updatedTicket) {
return res.json({'status': 'success', 'ticket': updatedTicket})
})
.catch(function(e) {
return res.status(400).json({'status': 'fail', 'error': e});
});
})
// DELETE a Ticket
.delete(function(req, res, next) {
Ticket.findByIdAndRemoveAsync(req.params.id)
.then(function(deletedTicket) {
res.json({'status': 'success', 'ticket': deletedTicket});
})
.catch(function(e) {
res.status(400).json({'status': 'fail', 'error': e})
});
});
module.exports = router;
// Users Route
const express = require('express');
const router = express.Router();
const User = require('../models/user');
router.route('/')
// READ all users.
.get(function(req, res, next) {
User.findAsync({})
.then(function(users) {
res.json(users);
})
.catch(next)
.error(console.error);
})
// CREATE new user.
.post(function(req, res, next) {
let user = new User();
let prop;
for (prop in req.body) {
user[prop] = req.body[prop];
}
user.saveAsync()
.then(function(user) {
console.log('success');
res.json({'status': 'success', 'user': user});
})
.catch(function(e) {
console.log('fail');
res.json({'status': 'error', 'error': e});
})
.error(console.error);
});
router.route('/:id')
// READ a single User by ID
.get(function(req, res, next) {
User.findOne({_id: req.params.id}, {})
.populate('tickets')
.exec(function (e, user) {
if (e) return console.error(e);
res.json(user);
})
})
// UPDATE a User
.put(function(req, res, next) {
let user = {};
let prop;
for (prop in req.body) {
user[prop] = req.body[prop];
}
User.updateAsync({_id: req.params.id}, user)
.then(function(updatedUser) {
return res.json({'status': 'success', 'user': updatedUser})
})
.catch(function(e) {
return res.status(400).json({'status': 'fail', 'error': e});
});
})
// DELETE a User
.delete(function(req, res, next) {
User.findByIdAndRemoveAsync(req.params.id)
.then(function(deletedUser) {
res.json({'status': 'success', 'user': deletedUser});
})
.catch(function(e) {
res.status(400).json({'status': 'fail', 'error': e})
});
});
module.exports = router;

Resources