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.
Related
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 ^^...
I want to populate the busNumber from bus Bus table to the trip table.
Here's the bus model
const busSchema = new mongoose.Schema(
{
busNumber: {
type: String,
unique: true,
required: true,
},
seats: {
type: Number,
},
},
{
timestamps: true,
}
);
now I want to show the bus number inside the trip table instead of bus._id. I know how to exclude data but don't know how to include data from other collections.
here's the route model where I included the bus model
const routeSchema = new mongoose.Schema({
location:{
type: mongoose.Schema.Types.ObjectId,
ref: 'Location',
required: true
},
duration: {
type: Number,
required: true,
},
Bus:{
type: mongoose.Schema.Types.ObjectId,
ref:"Bus",
required: true
},
date: {
type:String,
required: true
},
},
{
timestamps: true,
});
here's the query:
router.get("/trips", async (req, res) => {
if ((!req.query.departure && !req.query.arrival) || !req.query.date) {
return res.send({
error: "Please enter the data to get the trip",
});
}
const { departure, arrival, date } = req.query;
const locations = await Location.find({
"departureLocation.name": departure,
"arrivalLocation.name": arrival,
});
const ids = locations.map(location => location._id);
const routes = await Route.find({
$and: [{ location: { $in: ids } }, { date }],
}).select(['-busId', '-location', '-_id', '-createdAt', '-updatedAt', '-__v']);
return !routes ? res.status(404).send() : res.status(200).send(routes);
});
Here's the result I am getting https://i.stack.imgur.com/AwK5N.png
How to use the populate() function to get data from another collection in mongoose
use this code for your populate Bus key
router.get("/trips", async (req, res) => {
if ((!req.query.departure && !req.query.arrival) || !req.query.date) {
return res.send({
error: "Please enter the data to get the trip",
});
}
const { departure, arrival, date } = req.query;
const locations = await Location.find({
"departureLocation.name": departure,
"arrivalLocation.name": arrival,
});
const ids = locations.map(location => location._id);
const routes = await Route.find({
$and: [{ location: { $in: ids } }, { date }],
}).populate("Bus").select(['-busId', '-location', '-_id', '-createdAt', '-updatedAt', '-__v']);
return !routes ? res.status(404).send() : res.status(200).send(routes);
});
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
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);
Blog Schema:
{
body: { type: String, required: true },
title: { type: String, required: true },
published: { type: String, default: false },
date: { type: Date, default: Date.now },
user: { type: Schema.Types.ObjectId, ref: 'BlogUser' },
comments: [{ type: Schema.Types.ObjectId, ref: 'Comments' }],
likes:[{user:{ type: Schema.Types.ObjectId, ref: 'BlogUser' }}]
}
Like Route for adding a like:
exports.likeBlog = async (req, res) => {
const blog_id = req.params.blog_id;
const user_id = req.body.user_id;
await Blog.findByIdAndUpdate(
blog_id,
{
$push: {
likes: {
user: user_id,
},
},
},
{ new: true },
(err, newBlog) => {
if (err) res.status(422).json(err);
console.log(newBlog);
res.json(newBlog);
}
);
};
Blog Route for reciveing a blog:
exports.getBlogByID = async (req, res) => {
const blog_id = req.params.blog_id;
try {
const blog = await Blog.findById(blog_id)
.populate("comments")
.populate("user");
console.log(blog);
res.json(blog);
} catch (error) {
res.status(401).json(error);
}
};
When I add a like by calling Like route from client, I get a blog with correct amount of likes i.e only 1. But when I request blog from Blog Route it returns me with two objects inside "likes" array, with both same as each other(same id too). Why am I getting such result? Mind you that I call 'Blog Route' after calling 'Like Route'.
It worked fine after I changed "like route" to this:
exports.likeBlog = async (req, res) => {
const blog_id = req.params.blog_id;
const user_id = req.body.user_id;
const blog = await Blog.findById(blog_id);
blog.likes.unshift({ user: user_id });
await blog.save();
Blog.findById(blog_id)
.then((result) => {
res.json(result);
})
.catch((error) => {
res.status(501).json({ error });
});
};
I still don't know what's the difference between the two though.