Cannot read property '_id' of null (while making a post request) - node.js

at C:\Users\Deepak\Desktop\mern-ecommerce\mern-back-end\src\controller\cart.js:75:44
I am getting this error in controllers while making a post request.
Here is my code:
Controllers (Cart.js)
exports.getCartItems = (req, res) => {
Cart.findOne({ user: req.user._id })
.populate("cartItems.product", " _id name price productPictures")
.exec((error, cart) => {
if (error) return res.status(400).json({ error });
if (cart) {
let cartItems = {};
cart.cartItems.forEach((item, index) => {
cartItems[item.product._id.toString()] = {
_id: item.product._id.toString(),
name: item.product.name,
img: item.product.productPictures[0].img,
price: item.product.price,
qty: item.quantity,
};
});
res.status(200).json({ cartItems });
}
});
};
Routes (Cart.js)
router.post('/user/getCartItems', requireSignin, userMiddleware, getCartItems);
Models (Cart.js)
const mongoose = require('mongoose');
const cartSchema = new mongoose.Schema({
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
cartItems: [
{
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Products', required: true },
quantity: { type: Number, default: 1 }
}
]
}, {timestamps: true});
module.exports = mongoose.model('Cart', cartSchema);

Related

How do I update by using updteOne in mongodb?

router.post("/list/:shortId/recomment/:p_shortId", async (req, res, next) => {
const { shortId, p_shortId } = req.params;
const { comment } = req.body;
const email = req.tokenInfo.email;
try {
const authData = await User.findOne({email});
const postData = await Post.findOne({shortId});
const parentData = await Upment.findOne({p_shortId});
const newcomment = await Downment.create({
postType: 3,
author: authData,
post_id: postData,
parentment_id: parentData,
comment: comment
});
await Upment.updateOne({p_shortId}, {"$push": {"comments": newcomment._id}});
res.status(200).json({
result: 'recomment success'
})
} catch (err) {
err.message = `${err.message}, market post recomment error.`;
next(err);
}
});
updateOne doesn't work so I changed it to update
router.post("/list/:shortId/comment", async (req, res, next) => {
const { shortId } = req.params;
const { comment } = req.body;
const email = req.tokenInfo.email;
try {
const authData = await User.findOne({email});
const postData = await Post.findOne({shortId});
const newcomment = await Upment.create({
postType: 3,
author: authData,
post_id: postData,
comment: comment
});
// console.log(commentData);
await Post.updateOne({shortId}, {"$push": {"comments": newcomment._id}});
res.status(200).json({
result: 'comment success'
})
} catch (err) {
err.message = `${err.message}, market post comment error.`;
next(err);
}
});
then it worked. So I tried it in mongoDB Compass. like below
db.upments.updateOne({shortId: "wEhPg-wFqS0_2935vuZEQ"}, {"$push": {"comments": new ObjectId("62f38170e3dccbfe7a9842b2")}})
And this worked...
Only in the code, updateOne worked properly why this thing happens? how should I fix it?
thank you for listening question!!
here are schemas ^^ if you need anything more, let me know~
import mongoose from "mongoose"
import shortId from "./type/shortId.js"
const UpmentSchema = new mongoose.Schema({
shortId,
comment: String,
// closet:1, OOTD:2, board:3
postType: {
type: Number,
required: true
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
post_id: {
type : mongoose.Schema.Types.ObjectId,
ref: "Post",
required: true
},
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Downment",
}]
}, {
timestamps: true
}
);
const DownmentSchema = new mongoose.Schema({
shortId,
comment: String,
// closet:1, OOTD:2, board:3
postType: {
type: Number,
required: true
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
post_id: {
type : mongoose.Schema.Types.ObjectId,
ref: "Post",
required: true
},
parentment_id: {
type : mongoose.Schema.Types.ObjectId,
ref: "Upment",
required: true
},
}, {
timestamps: true
}
);
export const Upment = mongoose.model("Upment", UpmentSchema);
export const Downment = mongoose.model("Downment", DownmentSchema);
It was an error in update({p_shortId})
p_shortId is not in the upment model
await Post.updateOne({shortId}, {"$push": {"comments": newcomment._id}});
my mistake ^^...

Mongoose - Selecting and Sending Virtuals from Populated Fields

I am having a little trouble getting my mongoose virtuals to show up from deep populated fields. Here is the code of the backend function that is not behaving as I'd like it to:
exports.get_user_feed = async (req, res, next) => {
const options = { sort: { date: -1 } };
const user = await User.find(
{ username: req.params.user },
"username posts avatar followers following"
)
.populate({
path: "posts",
options,
populate: [
{
path: "author",
},
{ path: "comments", populate: { path: "author" } },
],
})
.sort({ "posts.date": 1 });
res.json({ ...user });
};
And here is the comment schema:
const mongoose = require("mongoose");
const { DateTime } = require("luxon");
const Schema = mongoose.Schema;
const CommentSchema = new Schema({
targetPost: { type: Schema.Types.ObjectId, ref: "Post", required: true },
author: { type: Schema.Types.ObjectId, ref: "User", required: true },
date: { type: Date, required: true },
content: { type: String, maxlength: 400 },
comments: [{ type: Schema.Types.ObjectId, ref: "Comment" }],
stars: [{ type: Schema.Types.ObjectId, ref: "User" }],
});
// Virtual for post's URL
CommentSchema.virtual("url").get(function () {
return "/" + this.targetPost.url + this._id;
});
// Virtual for formatted date.
CommentSchema.virtual("formatted_date").get(function () {
return (
DateTime.fromJSDate(this.date).toLocaleString(DateTime.DATE_MED) +
" at " +
DateTime.fromJSDate(this.date).toLocaleString(DateTime.TIME_SIMPLE)
);
});
//Export model
module.exports = mongoose.model("Comment", CommentSchema);
My goal is to get the comments from each post to also include the formatted_date of the comment, but this virtual is not getting included in the response that is sent - all the regular properties are being sent but not the virtual. Any help here would be appreciated.
Add this code in your Commnet Schema file before module.exports.
CommentSchema.method('toJSON', function () {
const {
...object
} = this.toObject({ virtuals:true });
return object;
});

How to Join model in Mongodb(Mongoose) and express?

I have 3 models 'User' , 'Doctor', 'Appointment', I want to let the user make an appointment then when he get his appointment I want to return the doctor name, also when the doctor get the appointment I want t return the user Name.
User Model :
const mongoose = require('mongoose');
const User = mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
})
const User = mongoose.model('User', User);
module.exports = { User };
Doctor Model :
const mongoose = require('mongoose');
const Doctor = mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
})
const Doctor = mongoose.model('Doctor', Doctor);
module.exports = { Doctor };
Appointment Model :
const mongoose = require('mongoose');
const Appointment = mongoose.Schema({
date: {
type: Date,
},
time: {
type: Date
},
_userID: {
type: mongoose.Types.ObjectId,
ref: 'User'
},
_doctorID: {
type: mongoose.Types.ObjectId,
ref: 'Doctor'
}
})
const Appoitment = mongoose.model('Appoitment', Appointment);
module.exports = { Appoitment };
Make and Get Appointment :
const express = require('express');
const { Appointment } = require('../DataBase/Models/appointment.model');
const router = express.Router();
router.get("/appointment/:id", async (req, res) => {
try {
const appointment = await Appointment.find({
user: req.params.id,
}).populate({
path: "doctor",
model: "Doctor",
});
res.send({
status: 200,
message: "SuccessFull",
Appointments: appointment,
});
} catch (error) {
res.send({
status: 400,
message: `Error: ${error}`,
});
}
});
router.post("/appointment", async (req, res) => {
try {
const makeAppointment = new Appointment(req.body);
const result = await makeAppointment.save();
res.send({
status: 200,
message: "SuccessFull",
Appointment: result,
});
} catch (error) {
res.send({
status: 404,
message: `Error : ${error}`,
});
}
});
My Question is How I can return the Appointment with the doctor Name the same with the User Name ??
in the .populate method, the path param is the name of the attribute in the model that you're trying to retrieve, so instead of path: 'doctor', you should be using '_doctorID' because you used this as the attribute name in the Appointment Model.
The same works for your query in the .find, you're querying the 'user' attribute, but you have _userID in your appointment model.
So, you have to 2 options:
Change _userID and _doctorID to user and doctor, this way should be better;
Or change user and doctor in your controller to _userID and _doctorID;
If you follow the first option, your code now should be something like:
Appointment Model:
const mongoose = require('mongoose');
const Appointment = mongoose.Schema({
date: {
type: Date,
},
time: {
type: Date
},
user: {
type: mongoose.Types.ObjectId,
ref: 'User'
},
doctor: {
type: mongoose.Types.ObjectId,
ref: 'Doctor'
}
})
const Appoitment = mongoose.model('Appoitment', Appointment);
module.exports = { Appoitment };
Appointment Controller:
router.get("/appointment/:id", async (req, res) => {
try {
const appointment = await Appointment.find({
user: req.params.id,
})
.populate({
path: "doctor",
select: "_id name",
});
res.send({
status: 200,
message: "SuccessFull",
Appointments: appointment,
});
} catch (error) {
res.send({
status: 400,
message: `Error: ${error}`,
});
}
});
if you want to select specific column .
it will look like .populate('author', 'name'). // only return the Author name

"UnhandledPromiseRejectionWarning: ValidationError" while placing order

Im trying to make an ecommerce app and the frontend is all done but when i place an order i get this message.
I rechecked every file but i cant find where its coming from. I followed the process from a udemy course but it just doesnt work. i got no response from the instructor and his code seems to work fine.
Here is the github master repo for the course.
I am stuck here for 10 days. HELP!
https://github.com/bluebits-academy/mern-stack-ecommerce
This is my Order.js
const mongoose = require('mongoose');
const orderSchema = mongoose.Schema({
orderItems: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'OrderItem',
required:true
}],
shippingAddress1: {
type: String,
required: true,
},
shippingAddress2: {
type: String,
},
city: {
type: String,
required: true,
},
zip: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
phone: {
type: String,
required: true,
},
status: {
type: String,
required: true,
default: 'Pending',
},
totalPrice: {
type: Number,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
dateOrdered: {
type: Date,
default: Date.now,
},
})
orderSchema.virtual('id').get(function () {
return this._id.toHexString();
});
orderSchema.set('toJSON', {
virtuals: true,
});
exports.Order = mongoose.model('Order', orderSchema);
/**
Order Example:
{
"orderItems" : [
{
"quantity": 3,
"product" : "5fcfc406ae79b0a6a90d2585"
},
{
"quantity": 2,
"product" : "5fd293c7d3abe7295b1403c4"
}
],
"shippingAddress1" : "Flowers Street , 45",
"shippingAddress2" : "1-B",
"city": "Prague",
"zip": "00000",
"country": "Czech Republic",
"phone": "+420702241333",
"user": "5fd51bc7e39ba856244a3b44"
}
**/
This is my api for order. orders.js
const {Order} = require('../models/order');
const express = require('express');
const { OrderItem } = require('../models/order-item');
const router = express.Router();
router.get(`/`, async (req, res) =>{
const orderList = await Order.find().populate('user', 'name').sort({'dateOrdered': -1});
if(!orderList) {
res.status(500).json({success: false})
}
res.send(orderList);
})
router.get(`/:id`, async (req, res) =>{
const order = await Order.findById(req.params.id)
.populate('user', 'name')
.populate({
path: 'orderItems', populate: {
path : 'product', populate: 'category'}
});
if(!order) {
res.status(500).json({success: false})
}
res.send(order);
})
router.post('/', async (req,res)=>{
const orderItemsIds = Promise.all(req.body.orderItems.map(async (orderItem) =>{
let newOrderItem = new OrderItem({
quantity: orderItem.quantity,
product: orderItem.product
})
newOrderItem = await newOrderItem.save();
return newOrderItem._id;
}))
const orderItemsIdsResolved = await orderItemsIds;
const totalPrices = await Promise.all(orderItemsIdsResolved.map(async (orderItemId)=>{
const orderItem = await OrderItem.findById(orderItemId).populate('product', 'price');
const totalPrice = orderItem.product.price * orderItem.quantity;
return totalPrice
}))
const totalPrice = totalPrices.reduce((a,b) => a +b , 0);
let order = new Order({
orderItems: orderItemsIdsResolved,
shippingAddress1: req.body.shippingAddress1,
shippingAddress2: req.body.shippingAddress2,
city: req.body.city,
zip: req.body.zip,
country: req.body.country,
phone: req.body.phone,
status: req.body.status,
totalPrice: totalPrice,
user: req.body.user,
})
order = await order.save();
if(!order)
return res.status(400).send('the order cannot be created!')
res.send(order);
})
router.put('/:id',async (req, res)=> {
const order = await Order.findByIdAndUpdate(
req.params.id,
{
status: req.body.status
},
{ new: true}
)
if(!order)
return res.status(400).send('the order cannot be update!')
res.send(order);
})
router.delete('/:id', (req, res)=>{
Order.findByIdAndRemove(req.params.id).then(async order =>{
if(order) {
await order.orderItems.map(async orderItem => {
await OrderItem.findByIdAndRemove(orderItem)
})
return res.status(200).json({success: true, message: 'the order is deleted!'})
} else {
return res.status(404).json({success: false , message: "order not found!"})
}
}).catch(err=>{
return res.status(500).json({success: false, error: err})
})
})
router.get('/get/totalsales', async (req, res)=> {
const totalSales= await Order.aggregate([
{ $group: { _id: null , totalsales : { $sum : '$totalPrice'}}}
])
if(!totalSales) {
return res.status(400).send('The order sales cannot be generated')
}
res.send({totalsales: totalSales.pop().totalsales})
})
router.get(`/get/count`, async (req, res) =>{
const orderCount = await Order.countDocuments((count) => count)
if(!orderCount) {
res.status(500).json({success: false})
}
res.send({
orderCount: orderCount
});
})
router.get(`/get/userorders/:userid`, async (req, res) =>{
const userOrderList = await Order.find({user: req.params.userid}).populate({
path: 'orderItems', populate: {
path : 'product', populate: 'category'}
}).sort({'dateOrdered': -1});
if(!userOrderList) {
res.status(500).json({success: false})
}
res.send(userOrderList);
})
module.exports =router;
And this is my order-item.js
const mongoose = require('mongoose');
const orderItemSchema = mongoose.Schema({
quantity: {
type: Number,
required: true
},
product: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Product'
}
})
exports.OrderItem = mongoose.model('OrderItem', orderItemSchema);
Do comment if you need any more codes.
The error :
ValidationError : OrderItem validation failed : product : Cast to ObjectId failed for value "{..}" at path "product"
means that: the "product" property in OrderItem expect an ObjectId, you can see it in the schema :
const orderItemSchema = mongoose.Schema({
quantity: {
type: Number,
required: true
},
product: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Product'
}
})
but you're passing an object into it here :
let newOrderItem = new OrderItem({
quantity: orderItem.quantity,
product: orderItem.product //<------ orderItem.product is an object
})
newOrderItem = await newOrderItem.save();
I think it should be :
let newOrderItem = new OrderItem({
quantity: orderItem.quantity,
product: orderItem.product.id // we only need the id of product
})
newOrderItem = await newOrderItem.save();
You may need to log orderItem.product before creating a new OrderItem to ensure the data inside it.

I am getting this error: Cannot read property 'likes' of null

I am getting error on console that : Cannot read property 'likes' of null
I am using postman for getting requests and putting response and response.
The array 'likes' is empty and here I am trying to insert the user id inside it but unable to insert it through unshift() method.
This is schema defined in a file Posts.js
const { text } = require('express');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
text: {
type: String,
required: true
},
name: {
type: String
},
avatar: {
type: String
},
likes: [
{
users: {
type: Schema.Types.ObjectId,
ref: 'users'
}
}
],
comment: [
{
users: {
type: Schema.Types.ObjectId,
ref: 'users'
},
text: {
type: String,
required: true
},
name: {
type: String,
},
avatar: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
],
date: {
type: Date,
default: Date.now
}
});
module.exports = Post = mongoose.model('post', PostSchema);
This is a express code for put request in file posts.js
const express = require('express');
const router = express.Router();
const { check, validationResult } = require('express-validator/check');
const auth = require('../../middleware/auth');
const Posts = require('../../models/Posts');
const User = require('../../models/User');
const { route } = require('./profile');
router.put('/like/:id', auth, async(req, res) => {
try {
const post = await Post.findById(req.params.id);
// Check if the post has already been liked
if(post.likes.filter(like => like.user.toString() === req.user.id).length > 0) {
return res.status(400).json({ msg: 'Post already liked' });
}
post.likes.unshift({ user: req.user.id });
await post.save();
res.json(post.likes);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
Here is the typo error I made. In the schema Posts.js in likes and comment array I wrote users instead of user.
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
text: {
type: String,
required: true
},
name: {
type: String
},
avatar: {
type: String
},
likes: [
{
users: { // Here it has to be user
type: Schema.Types.ObjectId,
ref: 'users'
}
}
],
comment: [
{
users: { //Here it has to be user
type: Schema.Types.ObjectId,
ref: 'users'
},

Resources