I am making a route in NodeJS using Mongoose which increments the rating of a subdocument of an object. I will post the models and route code below. When I execute the query in Postman, I get an empty json object back and a 400 error. This means somewhere in the query I am doing something wrong.
blogPost model
const BlogPostSchema = new Schema({
content: {
type: String,
validate: {
validator: (content) => content.length > 5,
message: 'Content must contain at least 6 characters.'
},
required: [true, 'Content must be filled in.']
},
rating: Number,
title: String,
user: { type: Schema.Types.ObjectId, ref: 'user' },
board: {type: Schema.Types.ObjectId, ref: 'board'},
comments: [commentSchema]
});
const BlogPost = mongoose.model('blogPost', BlogPostSchema);
module.exports = BlogPost;
comment schema
const CommentSchema = new Schema({
content: {
type: String,
validate: {
validator: (content) => content.length > 5,
message: 'Content must contain at least 6 characters.'
},
required: [true, 'Content must be filled in.']
},
user: { type: Schema.Types.ObjectId, ref: 'user' },
rating: Number
});
module.exports = CommentSchema;
NodeJS route
routes.put('/blogPosts/:id/comment/:idm', function(req, res) {
const blogPostId = req.param('id');
const commentId = req.param('idm');
BlogPost.findById(blogPostId)
.then((blogPost) => {
blogPost.comments.findByIdAndUpdate({_id: commentId}, {$inc: {rating: 1}});
})
.then((blogPost) => res.status(200).json({
'status': 'Comment rating is increased.'
}))
.catch((error) => res.status(400).json(error))
});
This is the response PostMan
All help is appreciated.
This was the error:
BlogPost.findById(blogPostId)
.then((blogPost) => {
blogPost.comments.findByIdAndUpdate({_id: commentId}, {$inc: {rating: 1}});
})
.then((blogPost) => res.status(200).json({
'status': 'Comment rating is increased.'
}))
Should be:
BlogPost.update({_id: blogPostId, 'comments._id': commentId}, {$inc:{'comments.$.rating':1}})
.then((blogPost) => res.status(200).json({
'status': 'Comment rating is increased.'
}))
Related
My Problem is i want after i create the categoryName and then i create the product properties, then i can push the product properties to the categoryProduct field.
I tried that using $push and it gives me an empty array in the db.
CallBack Function for creating a product
//Here i am getting the values from the body
//create an object
const productObject = new productSchema({
productName: req.body.productName,
productPrice: req.body.productPrice,
productCategory: req.body.productCategory,
productQuantity: req.body.productQuantity,
productSection: req.body.productSection,
productExDate: req.body.productExDate
})
//saving
productObject
.save()
.then(data => {
res.redirect('/halalMunchies/all-products');
})
.catch(err => {
res.status(500).send({
message: err.message || "Some error occured while creating a create operation"
});
});
//pushing inside the productCategory in the category model
categoryDB.findOneAndUpdate({ categoryName: req.body.productCategory }, { $push: { productsCategory: productObject._id } })
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
})
the output
{
_id: new ObjectId("61a62e619c17c622153c4d1a"),
categoryName: 'meat',
productsCategory: [],
__v: 0
}
In the categoryschema i have categoryname and productsCategory contains all the products that this category has.
Category Schema
var categorySchema = new mongoose.Schema({
//properties // shape of the documentation
categoryName: {
type: String,
required: true,
unique: true
},
productsCategory: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'productSchema',
required: true
}]
});
const categoryDB = mongoose.model('categorySchema', categorySchema);
In the productSchema one of it's properties is productCategory which it references to the categorySchema
var productSchema = new mongoose.Schema({
//defining the properties
productName: {
type: String,
unique: true,
required: [true, 'Product name is required'] // we can pass a message like this
},
productCategory: {
type: mongoose.Schema.Types.String,
ref: 'categorySchema',
required: [true, 'Category name is required'] // we can pass a message like this
},
productPrice: {
type: Float,
required: [true, 'Price name is required'] // we can pass a message like this
},
productQuantity: {
type: Number,
required: [true, 'Quantity name is required'] // we can pass a message like this
},
productSection: {
type: String,
required: [true, 'Section name is required'] // we can pass a message like this
},
productExDate: {
type: String,
required: [true, 'ExDate name is required'] // we can pass a message like this
}
})
const productDB = mongoose.model('productSchema', productSchema);
You can try it this way, assuming we're using an async function for the sake of simplicity to avoid .then .catch painful process:
const {
productData,
productCategory,
} = req.body;
const productObject = new productSchema({ ...productData });
await productObject.save();
const categoryObject = await categorySchema.findOne({ categoryName: productCategory });
if (!categoryObject) {
// Throw some error
}
await categoryObject.productsCategory.push(productObject._id);
await categoryObject.save();
// then make your redirect to /halalMunchies/all-products
EDIT
const {
productName,
productPrice,
productQuantity,
productSection,
productExDate,
productCategory,
} = req.body;
const productObject = new productSchema({
productName,
productPrice,
productCategory,
productQuantity,
productSection,
productExDate,
});
await productObject.save();
If you mean by productCategory "category id", then you should fetch by _id:
const categoryObject = await categorySchema.findOne({ _id: productCategory });
if (!categoryObject) {
// Throw some error
}
await categoryObject.productsCategory.push(productObject._id);
await categoryObject.save();
// then make your redirect to /halalMunchies/all-products
I have 2 models, category and story.
Story contains reference id of the category.
In controller story, I have a function mystories which should fetch all the story records of particular user along with category information.
I am getting data from story collection but not from category collection.
The result which I receive is something like this:
category_id: "5d10978c8e0f5d5380fdb3e6"
created_at: "2019-06-25T10:02:47.637Z"
created_by: "5d1066fba920ef2ccfe68594"
image: "uploads/1561456967615_164.jpg"
published: "no"
status: "pending"
text: "<p><strong>Fashion</strong> is a popular aesthetic expression in a certain time and context, especially in clothing, footwear, lifestyle, accessories, makeup, hairstyle and body </p>"
title: "New fashion"
__v: 0
_id: "5d11f14757f8616041616217"
It should however return category collection information instead of
category id.
Category model:
const mongoose = require('mongoose');
const categorySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
unique: true
},
status: {
type: String,
required: true,
enum: ['active','inactive','deleted']
},
created_at: { type: Date, default: Date.now },
created_by: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true},
});
module.exports = mongoose.model('Category', categorySchema);
Story model:
const mongoose = require('mongoose');
const storySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
title: {
type: String,
required: true
},
text: {
type: String,
required: true
},
category_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category',
required: true
},
image: {
type: String,
required: true
},
status: {
type: String,
required: true,
enum: ['pending','approved','deleted']
},
published: {
type: String,
required: true,
enum: ['yes','no']
},
created_at: { type: Date, default: Date.now },
created_by: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true},
});
module.exports = mongoose.model('Story', storySchema);
Controller code:
const mongoose = require('mongoose');
const Story = require('../models/story');
const Category = require('../models/category');
exports.mystories = async (req, res, next) => {
const user_id = req.userData.id;
const all_stories = await Story
.find({ created_by: user_id})
.populate('name','category')
.sort({ created_at: -1 })
.exec();
if(all_stories.length > 0) {
return res.status(200).json({
response: all_stories
});
}else {
return res.status(200).json({
response: []
});
}
};
exports.add_story = (req, res, next) => {
console.log(req.file);
const story = new Story({
_id: new mongoose.Types.ObjectId(),
title: req.body.story_title,
text: req.body.story_text,
category_id: req.body.story_category,
image: req.file.path,
status: 'pending',
published: 'no',
created_by: req.userData.id
});
story
.save()
.then(result => {
console.log(result);
res.status(200).json({
response: 'added_story'
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
})
});
};
populate takes the field name as it is given in story schema.
it should be :
.populate({path: 'category_id', select: 'name'})
//this error appear
{
"error": {
"message": "Cast to ObjectId failed for value \"events\" at path \"_id\" for model \"user\"",
"name": "CastError",
"stringValue": "\"events\"",
"kind": "ObjectId",
"value": "events",
"path": "_id"
}
}
//when execute this code
exports.get_all_events = (req, res, next) => {
Event.find({})
.populate("creator","name _id",user) // must define model reference
.then(result => {
console.log(result);
res.status(200).json({ result });
}).catch(err => {
console.log(err);
res.status(500).json({ error: err });
});
}
Event schema
const mongoose = require('mongoose');
// creat event schema
const eventSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'name is required']
},
location: {
type: String,
required: [true, 'location is required']
},
date: {
type: String,
required: [true, 'data is required']
},
description: {
type: String,
required: [true, 'description is required']
},
creator: {
_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "users"
}
}
});
module.exports = mongoose.model("events", eventSchema);
Userschema
const mongoose = require('mongoose');
const userSchema = mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
match: /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/
},
password: {
type: String,
required: true
},
name: {
type: String,
required: true
},
post: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "posts"
}
],
event: [
{
type: mongoose.Schema.Types.ObjectId,
// it point to collection
ref: "events"
}
]
});
module.exports = mongoose.model('users', userSchema);
it works great adding event to database and get single event it work but when i get all events from database throw casting error and can't make any updating on exist event
I think you are populating the events document little bit wrong.
Try this:
Event.find({})
.populate("creator._id","name _id")
.then(result => {
console.log(result);
res.status(200).json({ result });
}).catch(err => {
console.log(err);
res.status(500).json({ error: err });
});
I dont think you need any third argument in the .populate() function, You have already defined in your schema, where it should be populated from:
//look here, you have already defined it in your schema
creator: {
_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "users" //this says which collection it should be populated from
}
}
I hope it helps you out.
I want to make a route in NodeJS which increment the property of a subdocument but I don't know how to do it and the way I am doing it now does not seem to work.
blogPost model
const BlogPostSchema = new Schema({
content: {
type: String,
validate: {
validator: (content) => content.length > 5,
message: 'Content must contain at least 6 characters.'
},
required: [true, 'Content must be filled in.']
},
rating: Number,
title: String,
user: { type: Schema.Types.ObjectId, ref: 'user' },
board: {type: Schema.Types.ObjectId, ref: 'board'},
comments: [commentSchema]
});
const BlogPost = mongoose.model('blogPost', BlogPostSchema);
module.exports = BlogPost;
comment schema
const CommentSchema = new Schema({
content: {
type: String,
validate: {
validator: (content) => content.length > 5,
message: 'Content must contain at least 6 characters.'
},
required: [true, 'Content must be filled in.']
},
user: { type: Schema.Types.ObjectId, ref: 'user' },
rating: Number
});
module.exports = CommentSchema;
NodeJS route
routes.put('/blogPosts/:id/comment/:idm', function(req, res) {
const blogPostId = req.param('id');
const commentId = req.param('idm');
BlogPost.findById(blogPostId)
.then((blogPost) => {
blogPost.comments.findByIdAndUpdate({_id: commentId}, {$inc: {rating: 1}});
})
.then((blogPost) => res.status(200).json({
'status': 'Comment rating is increased.'
}))
.catch((error) => res.status(400).json(error))
});
This is the response Postman
All help is appreciated.
Well the promise hasn't been resolved, so what you can do is use async await functions or JavaScript generators which will make the client wait till the rating is incremented and the results json is sent.
Here's a tutorial on async-await and generators.
I have a mongoDB and I am trying to make a Nodejs server to manipulate the data in the database. I get a castError when I try to push a Comment to the Comments array in a BlogPost object.
Source code below, please tell me if you're missing important information.
Thanks in advance!
The route:
routes.post('/comments/push/:id', function(req, res) {
const blogPostId = req.param('id');
const commentProps = req.body;
BlogPost.findById(blogPostId)
.then((blogPost) => {
blogPost.comments.push(commentProps);
return blogPost.save();
})
.then((blogPost) => res.status(200).json({
'status': 'Comment is deleted.',
'comment': blogPost
}))
.catch((error) => res.status(400).json(error)) });
The BlogPost schema:
const BlogPostSchema = new Schema({
content: {
type: String,
validate: {
validator: (content) => content.length > 5,
message: 'Content must contain at least 6 characters.'
},
required: [true, 'Content must be filled in.']
},
rating: Number,
user: { type: Schema.Types.ObjectId, ref: 'user' },
board: {type: Schema.Types.ObjectId, ref: 'board'},
comments: [{
type: Schema.Types.ObjectId,
ref: 'comment'
}]
});
The Comment schema:
const CommentSchema = new Schema({
content: {
type: String,
validate: {
validator: (content) => content.length > 5,
message: 'Content must contain at least 6 characters.'
},
required: [true, 'Content must be filled in.']
},
user: { type: Schema.Types.ObjectId, ref: 'user' },
rating: Number
// board: Board
});
Here is the error in postman:
postman screen
Help would be greatly appreciated!
first make sure what's you are receiving in req.body, it's not good
to store directly from req.body.
second ref. comments Schema aspect a objectId while req.body is
Object itself. i'm not sure what are you going to do but it
something like blogPost.comments.push(req.body.someValidId);
third why 2 queries for simple update. you can use $push, $addToSet to push directly to comments or $pull to remove from comments.
BlogPost.findOneAndUpdate({
_id:blogPostId
}, {
$addToSet:{
comments : someValidId
}
}, {
new :true,
upsert:false
})
.then((blogPost) => {
res.status(200).json({
'status': 'Comment is deleted.',
'comment': blogPost
})
})
.catch((error) =>
res.status(400).json(error))
});