I'm trying to delete a comment on a post, but I'm unable to find the comment. When I'm console.log(post.comments) it shows me all the comments but still, I can't find the comment. The error was Comment not found which I wrote to find that comment is still there or not. But the comment was there I matched the id with it. Help me I'm new to NodeJs. Help me to fix this
*As a frontend I'm using react and redux I think the problem is in the backend, I've also tested with the postman. Can't delete the comment from postman.
here is the comment route and controller
router.route('/:id/comment/:comment_id').delete(protect, deleteComment);
export const deleteComment = asyncHandler(async (req, res) => {
const post = await Post.findById(req.params.id);
const comment = post.comments.find(
(comment) => comment._id === req.params.comment_id
);
if (!comment) {
res.status(404);
throw new Error('Comment not found');
}
//Check User
if (comment.user.toString() === req.user._id.toString()) {
post.comments = post.comments.filter(
({ id }) => id !== req.params.comment_id
);
await post.save();
return res.json(post.comments);
} else {
res.status(401);
throw new Error('User not authorized');
}
});
here is the post model
import mongoose from 'mongoose';
const postSchema = mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: [true, 'Please Author is required'],
},
title: {
type: String,
required: true,
},
desc: {
type: String,
required: true,
},
img: {
type: String,
},
isLiked: {
type: Boolean,
default: false,
},
isDisLiked: {
type: Boolean,
default: false,
},
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
],
disLikes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
],
comments: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
text: {
type: String,
required: true,
},
name: {
type: String,
},
pic: {
type: String,
},
date: {
type: Date,
default: Date.now,
},
},
],
categories: {
type: Array,
},
},
{
timestamps: { createdAt: 'created_at', updatedAt: 'modified_at' },
}
);
const Post = mongoose.model('Post', postSchema);
export default Post;
When you access to the _id you are accessing the instance of the ObjectId
You should try to compare with the id, that is a string representation of the _id
const comment = post.comments.find(
(comment) => comment.id === req.params.comment_id
);
Related
/I want to create a module section for a course website for which I will need a lesson schema as well so How can I design lesson schema , module schema , and course schema so they
work just how they are needed to workCurrently I am doing this/
import mongoose from 'mongoose'
const LessonSchema = new mongoose.Schema({
title: String,
content: String,
resource_url: String
})
const ModuleSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
lessons: [LessonSchema]
})
export const Module = mongoose.model('Module', ModuleSchema);
const CourseSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
required: 'Name is required'
},
price: {
type: String,
trim: true,
required: true
},
image: {
data: Buffer,
contentType: String
},
intro: {
type: String,
required :true
},
description: {
type: String,
trim: true
},
category: {
type: String,
required: 'Category is required'
},
updated: Date,
created: {
type: Date,
default: Date.now
},
instructor: {type: mongoose.Schema.ObjectId, ref: 'User'},
published: {
type: Boolean,
default: false
},
modules: [ModuleSchema]
})
export default mongoose.model('Course', CourseSchema)
Above was the schema and this is logic
const newLesson = async (req, res) => {
try {
let lesson = req.body.lesson
let course = await Course.find({modules: {_id: req.params.moduleId}})
console.log(course)
} catch (err) {
return res.status(400).json({
error: errorHandler.getErrorMessage(err)
})
}
}
const newModule = async (req, res) => {
try {
let lesson = req.body.lesson
let result = await Course.findByIdAndUpdate(req.course._id, {$push: {modules: {name: req.body.name, lessons: lesson}}, updated: Date.now()}, {new: true})
.populate('instructor', '_id name')
.exec()
res.json(result)
} catch (err) {
return res.status(400).json({
error: errorHandler.getErrorMessage(err)
})
}
}
**I have been brainstorming this from a while and cant get through it do you know how can I shape the schema and logic so that I can push lessons in module and then module in course schema ? **
I have review and product model.If user give review on specific product(id) then it is stored in review model database but i donot like to store user review in product model database .so, i used virtual populate in product model instead of child referencing.After using virtual properties,if we use product id to see details,we can see review of user in json format but not saved in database.But the problem is my virtual properties (In Product Model) not working as it doesnt show review of user in json format when i send the request in that product id which already have review by user(stored in review model database).what is the problem here?
User Review on Product (id) stored in database
Sending Request of that product id to see review of user in json format using virtual properties(but no review found in json)
In Product Model
const productSchema = new Schema({
name: {
type: String,
required: true,
trim: true,
},
slug: {
type: String,
required: true,
unique: true,
},
price: {
type: String,
required: true,
},
quantity: {
type: Number,
required: true,
},
description: {
type: String,
required: true,
trim: true,
},
offer: {
type: Number,
},
discount: {
type: Number,
},
productPictures: [{
img: {
type: String,
},
}, ],
mainCategory: {
type: mongoose.Schema.Types.ObjectId,
ref: "category",
required: [true, "It is a required field"],
},
sub1Category: {
type: mongoose.Schema.Types.ObjectId,
ref: "category",
required: [true, "It is a required field"],
},
sub2Category: {
type: mongoose.Schema.Types.ObjectId,
ref: "category",
required: [true, "It is a required field"],
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "admin",
required: true,
},
vendor: {
type: mongoose.Schema.Types.ObjectId,
ref: "vendor",
},
createdAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
updatedAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
},
{
toJson: { virtuals: true },
toObject: { virtuals: true },
}
);
productSchema.virtual("reviews", {
ref: "review",
foreignField: "product",
localField: "_id",
// justOne: true
});
const Product = mongoose.model("product", productSchema);
module.exports = Product;
In Review Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const moment = require("moment");
const reviewSchema = new Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
required: [true, "Review must belong to user"],
},
product: {
type: mongoose.Schema.Types.ObjectId,
ref: "product",
required: [true, "Review must belong to the product"],
},
review: {
type: String,
required: [true, "Review cannot be empty"],
},
rating: {
type: Number,
min: 1,
max: 5,
},
createdAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
updateddAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
}, {
toJson: { virtuals: true },
toObject: { virtuals: true },
});
// pre middleware and populating user and product(we can also do populate in getAllReview in controller)
reviewSchema.pre(/^find/, function(next) {
// ^find here is we use regex and can able to find,findOne ...etc
this.populate({
path: "product",
select: " _id name",
}).populate({
path: "user",
select: " _id fullName",
});
next()
});
const Review = mongoose.model("review", reviewSchema);
module.exports = Review;
In Review.js
const Review = require("../../models/Review.Models")
exports.createReview = async(req, res) => {
const review = await Review.create(req.body)
return res.status(201).json({
status: true,
review
})
}
exports.getAllReviews = async(req, res) => {
try {
const reviews = await Review.find()
return res.status(200).json({
status: true,
totalReviews: reviews.length,
reviews
})
} catch (error) {
return res.status(400).json({
status: false,
error
})
}}
In Product.js
const Product = require("../../models/Product.Models");
exports.getProductDetailsById = async(req, res) => {
try {
const { productId } = req.params;
// const { productId } = req.body;
if (productId) {
const products = await Product.findOne({ _id: productId })
.populate('reviews')
return res.status(200).json({
status: true,
products,
});
} else {
console.log("error display");
return res.status(400).json({
status: false,
error: "params required...",
});
}
} catch (error) {
return res.status(400).json({
status: false,
error: error,
});
}
try this in Product.js
try {
if (productId) {
const products = await Product.findOne({ _id: productId }).populate(
"reviews"
);
console.log(products);
if (products) {
return res.status(200).json({
status: true,
message: "Products is listed",
products,
reviw: products.reviews,
});
only need to add on response sending
return res.status(200).json({
status: true,
message: "Products is listed",
products,
reviw: products.reviews,
});
I'm trying to populate my post's author fields (which is are object ids) with the corresponding author objects which are in a separate collection.
My controller code is as follows:
exports.readPosts = async (req, res) => {
try {
const posts = await Post.find({ board: req.params.board });
await posts.populate("author").execPopulate();
res.send(posts);
} catch (err) {
res.status(400).send(err.message);
}
};
I'm at a loss as to why this isn't working as I have very similar code in another controller method that is working just fine.
All help greatly appreciated.
Below is the relevant Model file:
const mongoose = require("mongoose");
const postSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
trim: true,
},
content: { type: String, required: true, trim: true },
comments: [
{
comment: {
type: String,
required: true,
trim: true,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
date: {
type: Date,
default: Date.now(),
},
},
],
author: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User",
},
board: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Board",
},
},
{ timestamps: true }
);
const Post = mongoose.model("Post", postSchema);
module.exports = Post;
posts is an array of models. populate must be called on a model. The preferred way to do this is at query time. It probably works on your other controller because you are using a findOne so it is returning the model, not the Array.
const posts = Post
.find({ board: req.params.board })
.populate('author')
.exec();
So my goal is to retrieve posts with comments that are placed today with Mongoose.
First, I create a start-of-the-day UTC current date object with:
const todayForEvent = moment().startOf('day')
.utc().toDate();
this results in 2019-01-02T06:00:00.000Z
then I want to create a DB search with mongoose to fetch the posts where a comment has been placed today
const posts = await Post.find({
// From this user...
$and: [
// Find normal posts that has comments (recent interactions)
{ _posted_by: userId },
{ comments: { $exists: true, $ne: [] } },
{ 'comments.created_date': { $gte: todayForEvent } }
]
})
Third, I have mongoose comment documents that have a property created_date
const CommentSchema = new Schema({
created_date: {
type: Date,
default: moment().utc().toDate()
}
});
const Comment = mongoose.model('Comment', CommentSchema);
module.exports = Comment;
This is the result document after placing a comment
Everything looks OK but for some reason the posts array is still empty after the database search, can someone please tell me what I did wrong
EDIT: added post schema at request
const mongoose = require('mongoose');
const { Schema } = mongoose;
const PostSchema = new Schema({
content: {
type: String,
trim: true
},
_content_mentions: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
type: {
type: String,
required: true,
enum: ['normal', 'event', 'task']
},
_liked_by: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
comments_count: {
type: Number,
default: 0
},
comments: [{
type: Schema.Types.ObjectId,
ref: 'Comment'
}],
_group: {
type: Schema.Types.ObjectId,
ref: 'Group',
required: true
},
_posted_by: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
task: {
due_to: {
type: String,
default: null
},
_assigned_to: {
type: Schema.Types.ObjectId,
ref: 'User'
},
status: {
type: String,
enum: ['to do', 'in progress', 'done']
}
},
event: {
due_to: {
type: Date,
default: null
},
_assigned_to: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
},
created_date: {
type: Date,
default: Date.now
},
files: [{
orignal_name: {
type: String,
default: null
},
modified_name: {
type: String,
default: null
}
}]
});
const Post = mongoose.model('Post', PostSchema);
module.exports = Post;
EDIT 2: sample post document
{ _id: 5c2d14c30176ac30204809a8,
task: { due_to: null },
event: { due_to: null, _assigned_to: [] },
_content_mentions: [],
_liked_by: [],
comments_count: 1,
comments: [ 5c2d14dc0176ac30204809ab ],
content: '<p>poging 5 duust</p>',
type: 'normal',
_posted_by:
{ _id: 5c292e0e63deb43d9434f664,
profile_pic: 'default_user.png',
first_name: 'Jaspet',
last_name: 'Houthoofd' },
_group: 5c292db763deb43d9434f660,
created_date: 2019-01-02T19:45:07.710Z,
files: [],
__v: 0,
liked_by: [] }
**EDIT 3: sample comment **
{ _content_mentions: [],
created_date: 2019-01-02T21:10:04.456Z,
_id: 5c2d28c251f2bd332cdeaf0a,
content: '<p>hehe</p>',
_commented_by: 5c292db763deb43d9434f65f,
_post: 5c2d1dd254ca0429b470f000,
__v: 0 }
So the problem here is that you have two collections, posts and comments. Based on your Posts schema, comments array contains only ids that reference documents that are stored in second collection. That's why you can check whether that array exists and is not empty but you can't refer directly to these elements.
To fix that you can use $lookup to get those documents from comments into posts and then you can apply your date condition inside $match, try:
let posts = await Post.aggregate([
{ $match: { comments: { $exists: true, $ne: [] }, _postedBy: userId } },
{ $lookup: { from: "comments", localField: "comments", foreignField: "_id", as: "comments" } },
{ $match: { 'comments.created_date': { $gte: todayForEvent } } }
])
I'm learning MeanJS and I have problem with Mongoose. I have two models:
var CategorySchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Category name',
trim: true
},
slug: {
type: String,
default: '',
trim: true,
unique: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
articles: [{
type: Schema.ObjectId,
ref: 'Article'
}]
});
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
category: {
type: Schema.ObjectId,
ref: 'Category'
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
slug: {
type: String,
default: '',
trim: true,
unique: true
},
content: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
I'm saving articles like this:
exports.create = function(req, res) {
var article = new Article(req.body);
article.user = req.user;
article.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
Category.findById(article.category).exec(function(err, category) {
category.articles.push(article.category);
category.save(function(err, category) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(article);
}
});
});
}
});
};
and it's saving properly. The object looks like this:
{
"_id" : ObjectId("55b73bf97aa70c2c083655b0"),
"user" : ObjectId("55b115f35c7a03cc0e59d821"),
"articles" : [
ObjectId("55b73c017aa70c2c083655b2"),
ObjectId("55b73ee20bab5e8c0c7eadca")
],
"created" : ISODate("2015-07-28T08:23:21.562Z"),
"slug" : "motocycles",
"name" : "Motocycles",
"__v" : 2
}
and even when I'm counting records like {{ category.articles.length }} it's proper amount of articles in category and I can even print ObjectIds in the view. But when I add .populate('articles') like this:
exports.list = function(req, res) {
Category.find().sort('-created').populate('user', 'displayName').populate('articles').exec(function(err, categories) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(categories);
}
});
};
the length returns 0, ObjectIds disapears and I have no access to article properties just like there was no articles in category. Any ideas why is that happening?
Additional edit:
mongoose.model('Article', ArticleSchema);
mongoose.model('Category', CategorySchema);
It seems that the problem was with create function. I've changed few things and it started working:
exports.create = function(req, res) {
var article = new Article(req.body);
article.user = req.user;
article.save(function(err, savedArticle) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
Category.findById(article.category).exec(function (err, category) {
category.articles.push(savedArticle);
category.markModified('articles');
category.save(function (err, category) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(savedArticle);
}
});
});
}
});
};
I'm curious why it wasn't working even though Category object had proper Article ObjectId's.
First, some changes with regard to variables,schema instances and using ObjectId(The mongoose documentation isn't the best).
var categorySchema = new mongoose.Schema({
name: {
type: String,
required: 'Please fill Category name',
trim: true
},
slug: {
type: String,
trim: true,
unique: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: mongoose.Types.Schema.ObjectId,
ref: 'User'
},
articles: [{
type: mongoose.Types.Schema.ObjectId,
ref: 'Article'
}]
});
var articleSchema = new mongoose.Schema({
created: {
type: Date,
default: Date.now
},
category: {
type: mongoose.Types.Schema.ObjectId,
ref: 'Category'
},
title: {
type: String,
trim: true,
required: 'Title cannot be blank'
},
slug: {
type: String,
trim: true,
unique: true
},
content: {
type: String,
trim: true
},
user: {
type: mongoose.Types.Schema.ObjectId,
ref: 'User'
}
});
You need to export your models if you are using an MV* pattern with separate files for separate concerns. So...
exports.method = mongoose.model('Category',categorySchema);
exports.otherMethod = mongoose.model('Article',articleSchema);
. method and .otherMethod are from nodejs. Not sure about express equivalent or what express itself uses.
Then just name this file and require it using its path.