Axios.delete() not triggering as expected - node.js

So I've got a classes Model which contains an array of people who will attend the class, I am trying to remove people from the classes.
So this is the Model:
const mongoose = require('mongoose');
const classMembersSchema = mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
}
})
const classSchema = mongoose.Schema({
location: {
type: String,
required: true
},
type: {
type: String,
required: true
},
name: {
type: String,
required: true
},
time: {
type: String,
required: true
},
classMembers: [classMembersSchema]
});
module.exports = mongoose.model('createClass', classSchema);
The classMembers Array is the one I mentioned that I am trying to remove members from. classMembers: [classMembersSchema].
This is the axios.delete:
deleteClassHandler = () => {
axios.delete('/api/classes/' + this.props.id + '/user/' + this.props.userId)
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
}
This is the route:
router.delete('/:id/user/:userId', ClassesController.deleteUser);
This is the controller:
exports.deleteUser = (req, res) => {
GymClass.findById({
_id: req.params.id
}, 'classMembers', (err) => {
if (err) {
res.status(401).json({
message: "Error Occured!"
})
} else {
GymClass.findByIdAndDelete({
"classMembers.userId" : mongoose.Types.ObjectId(req.params.userId)
}, (err) => {
if(err) {
console.log('Keeps hitting here!');
res.status(401).json({
message: "Error Occured!"
})
} else {
res.status(200).json({
message: "Success!"
})
}
});
}
})
}
Everything works fine until it hits the console.log('Keeps hitting here!');
At the start of the function the req.params.id which is the class Id of which class we want to modify and the req.params.userId which is the user we want to remove from the Array inside the Model do have the right values but when it gets to that step it gives me the Error.
I'm thinking it could be that it is not finding this:
GymClass.findByIdAndDelete({
"classMembers.userId" : mongoose.Types.ObjectId(req.params.userId)
Since it's in an Array within the classMembers. Any idea or advice to get this to work? Many thanks.

Related

How to find top 10 most viewed and top 10 most liked data in mongoose

I have a Post table in mongo db. There are 1000 of post in the table. I tried following query to fetch top 10 most viewed and top 10 most liked post but I don't get any expected output. How to get that output, please help me.
This is my Post model in mongo db database where made two fields for views and likes.
const mongoose = require("mongoose");
const { Schema } = mongoose;
const postSchema = new Schema({
title: {
type: String,
required: true,
},
description: {
type: String,
},
image: {
type: String,
},
likes: [User],
views: {
type: Number,
},
createdBy: {
type: Schema.Types.ObjectId,
ref: "users",
},
createdAt: {
type: Date,
default: Date.now,
},
});
//Controller
topViewPosts(req, res) {
try {
Post.find()
.sort({ views: -1 })
.limit(10)
.then((posts) => {
console.log(posts);
res.status(200).json({
message: "Fetch seccessful",
posts: posts,
});
})
.catch(() => {
res.status(500).json({
error: error,
});
});
} catch (error) {
res.status(500).json({
error: error,
});
}
},
topLikePosts(req, res) {
try {
Post.find()
.sort({ likes: -1 })
.limit(10)
.then((posts) => {
console.log(posts);
res.status(200).json({
message: "Fetch seccessful",
posts: posts,
});
})
.catch(() => {
res.status(500).json({
error: error,
});
});
} catch (error) {
res.status(500).json({
error: error,
});
}
},
use the sort property :
router.get("/yourrouter", async(req, res) => {
try {
const variable = await Modal.find()
.sort(function(a,b) {
if (a.likes > b.likes) return -1
if (a.likes < b.likes) return 1
return 0
})
res.status(200).json(post)
} catch (error) {
res.status(500).json(error)
}
});

Mongoose: how to only populate, sort and return a nested object?

I have a User schema, with a messages array. The message array is filled by conversations id and referenced to a Conversation schema.
I want to fetch all conversations from a user, sort them by unread and then most recent messages. Finally, I must only return an array of lastMessage object.
For the moment, I have only managed to populate the whole user object.
Here is the Conversation Schema:
const conversationSchema = new mongoose.Schema(
{
name: { type: String, required: true, unique: true },
messages: [{ message: { type: String }, authorId: { type: String } }],
lastMessage: {
authorId: { type: String },
snippet: { type: String },
read: { type: Boolean },
},
},
{ timestamps: true }
);
conversationSchema.index({ name: 1 });
module.exports = mongoose.model("Conversation", conversationSchema);
And here is my code:
router.get("/conversations", async (req, res) => {
try {
const { userId } = req.query;
const user = await User.findById({ _id: userId }).populate("messages");
.sort({ updatedAt: 1, "lastMessage.read": 1 });
return res.json({ messages: user.messages });
} catch (err) {
console.log("error", err);
return res.json({ errorType: "unread-messages-list" });
}
});
How to do this?

Duplicate item returned from collection

Blog Schema:
{
body: { type: String, required: true },
title: { type: String, required: true },
published: { type: String, default: false },
date: { type: Date, default: Date.now },
user: { type: Schema.Types.ObjectId, ref: 'BlogUser' },
comments: [{ type: Schema.Types.ObjectId, ref: 'Comments' }],
likes:[{user:{ type: Schema.Types.ObjectId, ref: 'BlogUser' }}]
}
Like Route for adding a like:
exports.likeBlog = async (req, res) => {
const blog_id = req.params.blog_id;
const user_id = req.body.user_id;
await Blog.findByIdAndUpdate(
blog_id,
{
$push: {
likes: {
user: user_id,
},
},
},
{ new: true },
(err, newBlog) => {
if (err) res.status(422).json(err);
console.log(newBlog);
res.json(newBlog);
}
);
};
Blog Route for reciveing a blog:
exports.getBlogByID = async (req, res) => {
const blog_id = req.params.blog_id;
try {
const blog = await Blog.findById(blog_id)
.populate("comments")
.populate("user");
console.log(blog);
res.json(blog);
} catch (error) {
res.status(401).json(error);
}
};
When I add a like by calling Like route from client, I get a blog with correct amount of likes i.e only 1. But when I request blog from Blog Route it returns me with two objects inside "likes" array, with both same as each other(same id too). Why am I getting such result? Mind you that I call 'Blog Route' after calling 'Like Route'.
It worked fine after I changed "like route" to this:
exports.likeBlog = async (req, res) => {
const blog_id = req.params.blog_id;
const user_id = req.body.user_id;
const blog = await Blog.findById(blog_id);
blog.likes.unshift({ user: user_id });
await blog.save();
Blog.findById(blog_id)
.then((result) => {
res.json(result);
})
.catch((error) => {
res.status(501).json({ error });
});
};
I still don't know what's the difference between the two though.

findOneAndUpdate seems to be doubling my $inc count

I'm trying to post a comment on to my posts for my MERN app but I'm running into an issue where the comment (Posts.findOneAndUpdate) seems to posting the comments twice. I read a few posts on SO that described the issue to be the way mongoose handles queries but I must be missing something.
If anyone could explain what I'm doing wrong I would greatly appreciate it!
Route I'm using:
router.post('/newReply/:id', async function(req, res) {
const body = req.body
if (!body) {
return res.status(400).json({
success: false,
error: 'No text entered!',
})
}
const reply = new Replies(body)
if (!reply) {
return res.status(400).json({ success: false, error: err })
}
await Posts.findOneAndUpdate(
{ _id: req.params.id },
{
"$inc": { "replies": 1 },
"$push": { "comments": reply },
},
{
new: true
},
(err) => {
if (err) {
return res.status(404).json({
success: false,
error: err,
message: 'Post not found!',
})
}
return res.status(200).json({
success: true,
id: reply._id,
message: 'Reply created!',
reply: reply.reply,
points: reply.points,
createdAt: reply.createdAt
})
})
.catch(err => console.log(err))
})
Posts Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// Create Schema
const PostsSchema = new Schema({
post: {
type: String,
required: true
},
points: {
type: Number,
default: 0
},
voters: {
type: Array
},
upvotedBy: {
type: Array
},
downvotedBy: {
type: Array
},
createdAt: {
type: Date,
default: Date.now
},
replies: {
type: Number,
default: 0
},
comments: {
type: Array
},
user_id: {
type: 'string'
},
deleted: {
type: Boolean,
default: false
}
});
module.exports = Posts = mongoose.model("posts", PostsSchema);

TypeError: Cannot read property '_id' of undefined when using findOneAndRemove()

When I execute the function findOneAndRemove() and pass in the required parameters, it shows the error 'TypeError: Cannot read property '_id' of undefined'. My mongodb have the attribute '_id'
I tried findById(). It is working but if I defined findOneAndRemove({_id: req.params.id}), the error occurs.
**router**
router.delete('/delete/:id', async (req, res) => {
try {
var id = req.params.id;
if (!ObjectID.isValid(id))
return res.status(404).send();
let team = await Team.findOneAndDelete({ _id: id, createdBy: req.user._id });
console.log('team', team);
if (!team)
return res.status(404).send();
res.status(201).json({
message: 'Team Deleted',
result: { team }
});
} catch (e) {
console.log(e);
res.status(400).send(e);
}
});
**Team Model**
var mongoose = require('mongoose');
const teamSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
trim: true
},
country: {
type: String,
required: true,
trim: true
},
yearFounded: {
type: Date,
required: true
},
ground: {
type: String,
required: true,
trim: true
},
capacity: {
type: Number,
required: true,
},
manager: {
type: String,
required: false,
},
website: {
type: String,
required: false,
},
imagePath: {
type: String,
required: false,
},
description: {
type: String,
required: false
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
}
}, {
timestamps: true
})
teamSchema.index({ name: "text", manager: "text", ground: "text", country: "text" });
teamSchema.virtual('players', {
ref: 'Player',
localField: '_id',
foreignField: 'team'
})
const Team = mongoose.model('Team', teamSchema);
module.exports = Team
findOneAndRemove returns the removed document so if you remove a document that you later decide should not be removed, you can insert it back into the db. Ensuring your logic is sound before removing the document would be preferred to checks afterward IMO.
findOneAndDelete has the sort parameter which can be used to influence which document is updated. It also has a TimeLimit parameter which can control within which operation has to complete
try this
router.delete('/delete/:id', async (req, res) => {
try {
let id = {_id:req.params.id};
if (!ObjectID.isValid(id))
return res.status(404).send();
let team = await Team.findOneAndRemove({ _id: rid, createdBy: req.user._id });
console.log('team', team);
if (!team)
return res.status(404).send();
res.status(201).json({
message: 'Team Deleted',
result: { team }
});
} catch (e) {
console.log(e);
res.status(400).send(e);
}
});
The answer is I forget to add middleware 'authenticate' and hence the createdBy params req.user._id is forever undefined. The solution.
Routes
router.delete('/delete/:id', authenticate, async (req, res) => {
try {
var id = req.params.id;
if (!ObjectID.isValid(id))
return res.status(404).send();
let team = await Team.findOneAndRemove({ _id: id, createdBy: req.user._id });
if (!team)
return res.status(404).send();
removeImage(team.imagePath);
res.status(201).json({
message: 'Team Deleted',
result: { team }
});
} catch (e) {
console.log(e);
res.status(400).send(e);
}
});
Middleware
let authenticate = async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer ', '')
const decoded = jwt.verify(token, process.env.JWT_SECRET)
const user = await User.findOne({ _id: decoded._id, 'tokens.token': token })
if (!user) {
throw new Error()
}
req.token = token;
req.user = user;
next()
} catch (e) {
res.status(401).send({ error: 'Please authenticate.' })
}
};

Resources