unhandled promise rejection warning - couldn't store into database - javascript

Data comming from req is store in Comment collection but it is not store in Product collection and i'll get an error message
app.post("/products/:id/comments", function(req, res) {
//lookup campground using ID
Product.findById(req.params.id, function(err, product) {
if (err) {
console.log(err);
res.redirect("/products");
} else {
Comment.create(req.body.comment, function(err, comment) {
if (err) {
console.log(err);
} else {
console.log("aaaaaa");
product.comments.push(comment);
console.log("bbbbbb");
product.save();
console.log("cccccc");
res.redirect('/products/' + product._id);
}
});
}
});});
and following is Product
var mongoose = require("mongoose"),
productSchema = new mongoose.Schema({
name: String,
img: String,
price: Number,
desc: String,
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}],
created: {
type: Date,
default: Date.now()
}});module.exports = mongoose.model("Product", productSchema);
and this is Comment Schema
var mongoose = require("mongoose"),
commentSchema = mongoose.Schema({
text: String,
author: String
});module.exports = mongoose.model("Comment", commentSchema);
and i got following output :-
enter image description here
so it's store in commentSchema but it's not store in product.comments and when i run site that also redirect to products/:id, what i'm missing to store comment into database ??

If you don’t pass a callback function to save() then it will return a promise.
Therefore, you are getting the error as you have not added a catch.
Try passing a callback to save():
// ...
product.save(function(err, result) {
if (err) {
// Handle error
}
console.log("cccccc");
res.redirect('/products/' + product._id);
})

Related

MongoDB Cannot read property 'push' of undefined

I'm new to node.js, express and MongoDB, and still learning. The program had a runtime error when I tried some data association in MongoDB models. The reference has been included in the model already but push() method can't recognize it. The models look like this:
var mongoose = require('mongoose');
var commentSchema = new mongoose.Schema({
text: String,
author: String
});
var Comment = mongoose.model("comments", commentSchema);
module.exports = Comment;
and
var mongoose = require('mongoose');
var campgroundSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});
var Campground = mongoose.model("campgrounds", campgroundSchema);
module.exports = Campground;
The part where these two models are needed looks like this:
Campground.remove({}, function(err){
if(err){
console.log(err);
}else{
console.log("removed campground!");
data.forEach(function (seed) {
Campground.create(seed, function (err, data) {
if(err){
console.log(err);
} else{
console.log("camp created");
Comment.create(
{
text: "nice campsite!",
author: "haiderboi"
},function (err, comment) {
if(err){
console.log(err);
}else{
Campground.comments.push(comment);
Campground.save();
console.log("comment added");
}
}
);
}
});
});
}
});
It seems like the array is already defined in the Campground model so I can't tell the error. Thanks in advance!
Hey i was have problem like this in my project.And it wasn't working because my blogpost schema was like this:
var campgroundSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]});
And changed it to this:
var campgroundSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
comments: [
{
type: mongoose.Schema.Types.Mixed,
}
]});
Because up there you're referring ObjectId and you're setting an object inside your code.It's not match.So you should try like this
Found the problem!
Instead of doing
Campground.comments.push(comment);
I should do
data.comments.push(comment);
since I wanna push the comment to the current Campground object, I should use the object returned by the callback.

Express.js blogging application bug: filtering posts by category throws "Cast to ObjectId failed" failed error

I am working on a blogging application (click the link to see the GitHub repo) with Express, EJS and MongoDB.
I have Posts that are grouped into Categories, each in its own collection.
I run into a problem trying to filter posts by category. To obtain the post by category url, I turn the category name into a slug and use it this way:
Posted in <%= post.category.cat_name %>
In the public routes file I have:
const express = require('express');
const postsController = require('../../controllers/front-end/posts');
// Express router
const router = express.Router();
// Get Posts
router.get('/', postsController.getPosts);
// Get Single Post
router.get('/:id', postsController.getSinglePost);
// Get Posts by Category
router.get('/:catname', postsController.getPostsByCategory);
module.exports = router;
The Post model:
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
short_description: {
type: String,
required: true
},
full_text: {
type: String,
required: true
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category'
},
post_image: {
type: String,
required: false
},
updated_at: {
type: Date,
default: Date.now()
},
created_at: {
type: Date,
default: Date.now()
}
});
module.exports = mongoose.model('Post', postSchema);
The Category model:
const mongoose = require('mongoose');
const categorySchema = new mongoose.Schema({
cat_name: {
type: String,
required: true
},
updated_at: {
type: Date,
default: Date.now()
},
created_at: {
type: Date,
default: Date.now()
}
});
module.exports = mongoose.model('Category', categorySchema);
In the Posts controller I turn the slug back into category name to filter posts by category name:
exports.getPostsByCategory = (req, res, next) => {
function titleize(slug) {
var words = slug.split("-");
return words.map(function(word) {
//return word;
return word.charAt(0).toUpperCase() + word.substring(1).toLowerCase();
}).join(' ');
}
const postCategory = titleize(req.params.catname);
const posts = Post.find({ cat_name: postCategory }, (err, posts) => {
console.log('Category: ', postCategory);
if(err){
console.log('Error: ', err);
} else {
res.render('default/index', {
moment: moment,
layout: 'default/layout',
website_name: 'MEAN Blog',
page_heading: 'XPress News',
page_subheading: 'A MEAN Stack Blogging Application',
posts: posts.reverse(),
});
}
}).populate('category');
};
The line console.log('Category: ', postCategory) outputs Category: Favicon.ico instead of the category name.
What am I doing wrong?
if I read this correctly, res is expect json pairs.
I am guessing your post.reverse() does not output in json format.
first of all - look at the moment where you ask DB - you need to await the answer, so you should use Promise.than() or async/await in your routes ...
Another one from request you get STRING as parameter - but in mongo schema you have Object...
So you should receive smth like "CastError: Cast to ObjectId failed...",
it depends on your vision you can: first select category from category.db => so you receive category Object after that you can search the posts using this object ..., or you can first populate results of posts by category (obtain plain category fields) and make further search...
category in your post-schema is a $ref to the category-schema, which is why it holds an objectId. In order to reference and actually query your category-schema while using .find(), you need to populate it first:
Post.
find({}).
populate({
path: 'category',
match: { cat_name: postCategory}
}).
exec((err, posts) => {
// ...
});
The mongoose documentation for $ref/populate() is a bit hidden here, in case you want know more about it.
Thanks to Lilian Baxan, here is the right getPostsByCategory method in controllers\front-end\posts.js:
const Category = require('../../models/categories');
//more code here
exports.getPostsByCategory = async (req, res, next) => {
function titleize(slug) {
var words = slug.split("-");
return words.map(function(word) {
//return word;
return word.charAt(0).toUpperCase() + word.substring(1).toLowerCase();
}).join(' ');
}
const postCategory = titleize(req.params.catname);
const singleCategory = await Category.findOne({cat_name:postCategory})
const posts = await Post.find({ category : singleCategory }, (err, posts) => {
if (err) {
console.log('Error: ', err);
} else {
res.render('default/index', {
moment: moment,
layout: 'default/layout',
website_name: 'MEAN Blog',
page_heading: 'XPress News',
page_subheading: 'A MEAN Stack Blogging Application',
posts: posts.reverse(),
});
}
}).populate('category');
};

Issue with adding comment

I am making a node API. I am stuck at adding a comment to a story.
I am able to create a comment but instead of pushing it to a given story, it was trying to create a new instance of story.
Story.findOne(req.params.id, (err, foundstory) => {
if(err){
res.status(500).json({msg:err})
}else{
let comment = new Comment()
comment.body = req.body.body
comment.author = req.body.author
console.log(foundstory)
//save comment//
comment.save((err, comment) => {
if(err){
res.status(500).json({msg:err})
}else{
//pushing comment to comments array (ref) in story
foundstory.comments.push(comment)
foundstory.save()
res.status(200).json({msg:"Comment saved"})
}
})
}
})
Story Schema
import mongoose from 'mongoose'
import User from './user'
import Comment from './comment'
const Schema = mongoose.Schema
const ObjectID = mongoose.Schema.Types.ObjectId
const storySchema = new Schema({
//subdoc ref from user
author: {type: ObjectID, ref: 'User'},
//subdoc ref from comment
comments: [{
type: ObjectID,
ref: 'Comment'
}],
//contents of story//
title: {type: String, required: true},
body: {type: String, required: true},
date: {type: Date, default: Date.now()},
tags: [{type: String}]
})
module.exports = mongoose.model('Story', storySchema)
Comment Schema
import mongoose from 'mongoose'
import User from './user'
const Schema = mongoose.Schema
const ObjectID = mongoose.Schema.Types.ObjectId
const commentSchema = new Schema({
body : {type: String, required: true},
author: {type: ObjectID, ref: 'User'}
})
module.exports = mongoose.model('Comment', commentSchema)
I have an array of type "Comment" in my "Story" schema. My attempt is to push those comment to that array.
try changing your code like this:
Story.findById(req.params.id, (err, foundstory) => {
if (err) res.status(500).json({
msg: err
});
else if (!foundStory) res.status(400).json({
msg: "Story Not Found"
});
else {
let comment = new Comment();
comment.body = req.body.body;
comment.author = req.body.author;
//save comment//
comment.save(async (err, comment) => {
if (err) res.status(500).json({
msg: err
});
else {
foundstory.comments.push(comment._id);
await foundstory.save();
res.status(200).json({
msg: "Comment saved"
})
}
})
}
})
I've changed the findOne() method with findById(), also the 'foundstory.save()' method is an asynchronous call, so i used async\await to handle it.
Hope this helps :)

Unable to save to an asssociate array in mongodb using mongoose

var mongoose = require("mongoose"),
campground = require("./models/campground"),
comment = require("./models/comment");
var data = [{
name: "Offside Lake",
image: "https://images.unsplash.com/photo-1504280390367-361c6d9f38f4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
description: "Whatever evrr"
},
{
name: "Reality Check",
image: "https://images.unsplash.com/photo-1517824806704-9040b037703b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
description: "wabdiwyu"
},
{
name: "Wawu Land",
image: "https://images.unsplash.com/photo-1508873696983-2dfd5898f08b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
description: "Just be feeling Wawu"
}
];
var text = {
text: "Hullabaloo",
author: "Olalaa"
};
campground.comments = new Array();
function seedDB() {
campground.deleteMany({}, function(err) {
if (err) {
console.log(err);
} else {
console.log("removed");
data.forEach(function(camp) {
campground.create(camp, function(err, camp) {
if (err) {
console.log(err);
} else {
console.log("Successfully added");
comment.create(text, function(err, comment) {
if (err) {
console.log(err);
} else {
campground.comments.push(comment);
campground.save();
console.log("comment added");
}
});
}
});
});
}
});
}
I have two mongoose models campground and comment. Inside the campground schema, I have the comments associative array in the campground schema. I am trying to add comments to my comments array but I am getting the error - campground.save is not a function. Even tried campground.markModified("comment") then campground.save(), getting the same error
//my campground schema
var mongoose = require("mongoose");
var campSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: "comment"
}]
});
module.exports = mongoose.model("Camp", campSchema);
//my comment schema
var mongoose = require("mongoose");
var commentSchema = mongoose.Schema({
text: String,
author: String
})
module.exports = mongoose.model("comment", commentSchema);
If I understand what you are trying to do, you are trying to create a campground and place the comments inside.
If that is so, then the code may look something like this (placed everything in one file):
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser: true});
var data = [
{
name: "Offside Lake",
image: "https://images.unsplash.com/photo-1504280390367-361c6d9f38f4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
description: "Whatever evrr"
}, {
name: "Reality Check",
image: "https://images.unsplash.com/photo-1517824806704-9040b037703b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
description: "wabdiwyu"
}, {
name: "Wawu Land",
image: "https://images.unsplash.com/photo-1508873696983-2dfd5898f08b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
description: "Just be feeling Wawu"
}
];
const comment = mongoose.model('comment', new mongoose.Schema({
text: String,
author: String
}));
const campground = mongoose.model('Camp', new mongoose.Schema({
name: String,
image: String,
description: String,
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: "comment"
}]
}));
var text = {
text: "Hullabaloo",
author: "Olalaa"
};
campground.deleteMany({}, function(error) {
if (error) {
console.error(error);
return;
}
console.log("Removed");
data.forEach(function(camp) {
campground.create(camp, function(error, newCamp) {
if (error) {
console.error(error);
return;
}
console.log("Successfully added");
comment.create(text, function(err, newComment) {
if (err) {
console.error(err);
return;
}
newCamp.comments.push(newComment);
newCamp.save();
console.log("Comment added");
})
});
})
})
The problem was due to the fact that you kept the same name throughout and that might have confused you a bit.
What you wanted to do was camp.comments.push(comment) camp.save() instead of campground.comments.push(comment) and campground.save() respectively.
As a friendly advice:
Switch to using promises instead of callbacks, you may set yourself up for what is known as Callback hell
As much as possible try not to rely on the closure nature of JavaScript and keep naming your variables the same throughout. That leads to problems like what you are experiencing now

Mongoose - Model.deleteOne() is deleting the entire collection instead of a single document

I have a User model that contains an array of customers. I want to delete a specific customer based on the customer _id. From what I've read in the Mongoose docs, I should use Model.deleteOne to delete a single document.
Here is my attempt
User Schema (it's been shortened for brevity):
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username: {
type: String,
default: ''
},
password: {
type: String,
default: '',
},
registerDate: {
type: Date,
default: Date.now()
},
customer: [{
name: {
type: String,
default: '',
},
email: {
type: String,
default: 'No email name found'
},
fleet: [{
unitNumber: {
type: String,
default: 'N/A',
}
}]
}]
});
module.exports = mongoose.model('User', UserSchema);
Here is a look at the route and controller:
const express = require('express');
const router = express.Router();
const customer_controller = require('../../controllers/customers');
router.delete('/customers/:custid', customer_controller.customer_remove);
module.exports = router;
And finally the controller:
exports.customer_remove = (req, res) => {
const { params } = req;
const { custid } = params;
User.deleteOne({ 'customer._id': custid }, (err) => {
if (err)
throw err;
else
console.log(custid, 'is deleted');
});
};
From what I thought, User.deleteOne({ 'customer.id': custid }) would find the customer _id matching the custid that is passed in via the req.params. When I test this route in Postman, it deletes the entire User collection that the customer is found in, instead of just deleting the customer. Can I get a nudge in the right direction? I feel like I am close here (or not lol).
deleteOne operates at the document level, so your code will delete the first User document that contains a customer element with a matching _id.
Instead, you want update the user document(s) to remove a specific element from the customer array field using $pull. To remove the customer from all users:
User.updateMany({}, { $pull: { customer: { _id: custid } } }, (err) => { ...
Using Mongoose you can do this:
model.findOneAndUpdate({ 'customer._id': custid }, {$pull: { $pull: {
customer: { _id: custid } }}, {new: true}).lean();
Removing subdocs.
Each sub document has an _id by default. Mongoose document arrays have a special id method for searching a document array to find a document with a given _id.
Visit: https://mongoosejs.com/docs/subdocs.html
parent.children.id(_id).remove();
Use async-await, may be that will work.
exports.customer_remove = async (req, res) => {
const { params } = req;
const { custid } = params;
try {
await User.deleteOne({ 'customer._id': custid });
console.log(custid, 'is deleted');
} catch (err) {
throw err;
}
};

Categories

Resources