(mongoose) put method does not work - node.js

I am creating web API using mongoose.
POST and GET work, but I have no idea how to implement PUT method in mongoose.
Here is what I created:
board.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const config = require('../config/database');
const BoardSchema = mongoose.Schema({
_id: {
type: String
},
position: {
type: [String]
}
});
const Board = module.exports = mongoose.model('boards', BoardSchema);
module.exports.getBoardById = function (id, callback)
{
Board.findById(id, callback);
}
module.exports.addBoard = function (newBoard, callback)
{
newBoard.save(callback);
}
module.exports.updateBoard = function (newBoard, callback)
{
newBoard.save(callback);
}
users.js
router.put('/board/:id', (req, res, next) =>
{
let newBoard = new Board({
_id: req.params.id,
position: req.body.position
});
Board.updateBoard(newBoard, (err, board) =>
{
if (err)
{
res.json({ newBoard: newBoard, success: false, msg: "Failed to update board" });
}
else
{
res.json({ newBoard: newBoard, success: true, msg: "Board added" });
}
});
});;
Here, in the board.js, I created methods for adding a new board and updating to existing board. .addBoard is working correctly and am able to test it using Postman. But, .updateBoard adds the data when the data does not exist, but does not update any data and returns false as response (just like POST does). Is there any way I can make the PUT method works?
Thank you!

Please let me know if this works for you! I want to introduce you to http://mongoosejs.com/docs/api.html#findbyidandupdate_findByIdAndUpdate
router.put('/board/:id', (req, res) => {
const {id: _id} = req.params // Assigning id to _id which is a es6 feature. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
const {position} = req.body
const newBoard = {
_id,
position
}
Board.findByIdAndUpdate(
_id,
newBoard,
(err, updatedBoard) => {
if (err) {
res.json({
newBoard,
success: false,
msg: 'Failed to update board'
})
} else {
res.json({newBoard, success: true, msg: 'Board added'})
}
}
)
})

why are you using save method while updating?
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const config = require('../config/database');
const BoardSchema = mongoose.Schema({
_id: {
type: String
},
position: {
type: [String]
}
});
const Board = module.exports = mongoose.model('boards', BoardSchema);
module.exports.getBoardById = function (id, callback)
{
Board.findById(id, callback);
}
module.exports.addBoard = function (newBoard, callback)
{
newBoard.save(callback);
}
module.exports.updateBoard = function (condition, update, callback)
{
Board.update(condition,update,callback);
}
in controller
router.put('/board/:id', (req, res, next) =>
{
let newBoard = new Board({
_id: req.params.id,
position: req.body.position
});
Board.updateBoard({ _id: req.params.id } ,newBoard, (err, board) =>
{
if (err)
{
res.json({ newBoard: newBoard, success: false, msg: "Failed to update board" });
}
else
{
res.json({ newBoard: newBoard, success: true, msg: "Board added" });
}
});
});
try this.

As you are using req.body i think you are trying to call a put request from a form (sometimes happens with AJAX requests also). For doing that use method-overide. And set the xhr header as given in the documentation. This will surely work.

Related

throw new error_1.MongoInvalidArgumentError('Update document requires atomic operators');

I'm getting (throw new error_1.MongoInvalidArgumentError('Update document requires atomic operators'); )
this type of error
Here is the full code for put endpoint:
app.put('/todo/:id', async (req, res) =>
{
const id = req.params.id; const data = req.body;
console.log(data);
const filter = { _id: ObjectId(id) };
const options = { upsert: true };
const updateDoc = { $set: { name: data.name, message: data.message, }, };
const result = await dataCollections.updateOne(filter, options, updateDoc);
res.send(result);
});
You are sending the parameters in the wrong order, update document comes before options, try this:
const result = await dataCollections.updateOne(filter, updateDoc, options);

UnhandledPromiseRejectionWarning: ReferenceError: book is not defined

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

How to delete a doc with id with mongoose?

I want to delete a doc with id in mongoose. It executes the method but doesn't delete that doc in MongoDB Altas.
Note:Everthing is correct and also Passing id correctly in PostMan.
here is my controller :
const Post = require("../models/Post");
const mongoose = require("mongoose");
exports.postPost = async (req, res) => {
try {
const post = await new Post({
_id: new mongoose.Types.ObjectId(),
title: req.body.title,
desc: req.body.desc,
}).save();
console.log("Saved in db!");
return res.status(201).json({
success: true,
data: post,
});
} catch (error) {
return res.status(500).json({
success: false,
message: "Server Error",
});
}
};
exports.deletePost = async (req, res) => {
let postID = req.params.id;
await Post.deleteOne({ _id: postID }, (err, data) => {
if (err) {
res.status(500).json({
message: "Something went wrong, please try again later.",
});
} else {
res.status(200).json({
message: "Post Deleted",
data: data,
});
}
});
};
here is my posts route:
const express = require("express");
const router = express.Router();
const {
postPost,
deletePost,
} = require("../controllers/posts_controller");
router.route("/:id").delete(deletePost);
router.route("/").post(postPost);
module.exports = router;
here is my postman :
here is my mongodb altas:
use the findOneAndDelete({_id:postId}) instead of deleteOne in posts controller
Or
use findByIdAndDelete(postId) instead of deleteOne in posts controller
exports.deletePost = async (req, res) => {
let postID = req.params.id;
await Post.findByIdAndDelete(postID, (err, data) => {
if (err) {
res.status(500).json({
message: "Something went wrong, please try again later.",
});
} else {
res.status(200).json({
message: "Post Deleted",
data: data,
});
}
});
};

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!!

User details not getting updated in nodejs

I am trying to get the functionality of user updating his profile while being logged in.But when i try to update the fields,for example the "name" field,it doesn't get updated although it runs without any error.It remains the same even after running properly.
Here is my code.
const filterObj = (obj, ...allowedFields) => {
const newObj = [];
Object.keys(obj).forEach((el) => {
if (allowedFields.includes(el)) newObj[el] = obj[el];
});
return newObj;
};
exports.updateMe = catchAsync(async (req, res, next) => {
if (req.body.password || req.body.passwordConfirm) {
return next(new AppError('This route is not for password updates.', 400));
}
//Filtering out field names that are not allowed to be updated
const filteredBody = filterObj(req.body, 'name', 'email');
//Updating the user data
const updatedUser = await User.findByIdAndUpdate(req.user.id, filteredBody, {
new: true,
runValidators: true,
});
res.status(200).json({
status: 'success',
data: {
user: updatedUser,
},
});
});

Resources