Deleting Subdocument from an array of schema - javascript

I have a user schema and each user have a profile in which he has a collection of book, and the user wants to remove a single book from the bookCollection, I have tried my code is at the bottom. The user schema is as follows:
var bookSchema = new Schema({
title: {
type: String,
required: true,
},
author: {
type: String,
required: true,
},
publisher: {
type: String,
default: "not set"
},
desc: {
type: String,
default: "not set"
},
availableAs: {
type: String, //either hardcopy or softcopy
required: true
},
price: {
type: Number,
default: 0
},
category: {
type: String,
default: "not set"
},
imageurl: {
type: String,
default: 'nobook.png'
},
bookurl: {
type: String,
default: ''
},
softcopy_available: {
type: Number,
default: 0
}
});
var userSchema = new Schema({
admin: {
type: Boolean,
default: false
},
bookCollection: [bookSchema]
});
This is what I am trying, but deletion is not working, sometimes it shows error and the page keeps on loading.
router.post('/', (req, res, next) => {
console.log(req.body.bookid);
var id=req.body.bookid;
users.findOne({
})
.then((user1) =>
user1.bookCollection.pull(req.body.bookid._id);
})
.catch((err) => {
next(err)
});
});

Why don't you use updateOne, or UpdateMany to pull the book from bookcollection, if you need to remove from a single user
var ObjectId = mongoose.Types.ObjectId;
users.updateOne({_id: ObjectId(user_id)},{ $pull: { bookCollection: { _id: ObjectId(req.body.bookid._id) } }})
.then((results) =>
// results of your update query
})
.catch((err) => {
next(err)
});
If want to remove a certain book from all the users
var ObjectId = mongoose.Types.ObjectId;
users.updateMany({},{ $pull: { bookCollection: { _id: ObjectId(req.body.bookid._id) } }})
.then((results) =>
// results of your update query
})
.catch((err) => {
next(err)
});

Related

How can i create a module for a course website using mongoDB and node.js

/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 ? **

Failed to delete the a comment on post?

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

why Virtual Populate not working on Node js and mongoose? Scenario : Product and Review by user

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,
});

Find One and Update in Mongoose with reference to other models is not working

I have a model named OrderModel and it has reference to other models as well
const orderSchema = new Schema({
_id: Schema.Types.ObjectId,
address: { type: addressSchema, required: false },
items: [{ type: Schema.Types.ObjectId, ref: 'Items' }],
date: { type: Date, default: moment(new Date()) },
user: { type: Schema.Types.ObjectId, ref: 'Users' },
is_completed: { type: Boolean, required: true, default: false },
is_canceled: { type: Boolean, required: true, default: false }
});
and when I want to update this model, using PATCH, it is giving me an error,
CastError: Cast to [ObjectId] failed for value "["5f0c9493f833e23a0028bd31,5f0c9429f833e23a0028bd2f"]" at path "items"
Here is how I do it in my code,
router.patch('/order', (req, res) => {
const query = { _id: req.body._id };
const _token = req.headers.authorization;
let data = req.body;
jwt.verify(_token, process.env.AUTH_TOKEN_KEY, (err, decoded) => {
console.log(query);
if (err) {
res.json({ message: 'Token Invalid'.err });
} else {
OrderModel.findOneAndUpdate(query, data, { new: true }, (err, doc) => {
console.log(doc,query);
if (doc) {
return res.json({ message: 'Succesfully saved', data: doc });
}
return res.json({ message: `No order found for id ${req.body._id}` });
});
}
})
})
i have two items as an Array, sent from frontend
{
"_id": "5f8f1b7b29cbed4a8495d646",
"items":"5f0c9493f833e23a0028bd31,5f0c9429f833e23a0028bd2f",
"user":"5f06060110b7881ac0244005",
"address":{
"line_1": "Address line 1",
"line_2": "Address line 1",
"city": "Los Angeles",
"state": "California",
"pin": "90210"
},
"is_completed": false,
"is_canceled": false
}
what am i doing wrong here?

Mongoose - when use populate no records otherwise array of records

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.

Categories