I'm facing a weird issue while placing order in my ecommerce. when i place order the 1st time it registers and saves the order in my database but when the same user tries to place order the 2nd time i get a weird error.
my api call -
useEffect(()=>{
const makeRequest = async ()=>{
try{
const res = await userRequest.post("/checkout/pay", {
tokenId:stripeToken.id,
amount: cart.total,
})
try {
userRequest.post('/orders', {
userId: userr._id,
products: cart.products.map((item) => ({
productName: item.title,
productId: item._id,
quantity: item._quantity,
})),
amount: cart.total,
address: res.data.billing_details.address,
})
history('/success');
} catch(err) {
console.log(err)
}
}catch(err){
console.log(err)
}
};
stripeToken && makeRequest();
}, [stripeToken, cart.total, history])
order model -
const mongoose = require('mongoose');
const orderSchema = new mongoose.Schema(
{
userId: {type: String, required: true},
products: [
{
productName: {type: String},
productId: {type: String},
quantity: {type: Number, default: 1},
},
],
amount: {type:Number, required:true},
address: { type: Object, required:true },
status: {type: String, default: 'pending'},
}, {timestamps: true}
);
module.exports = mongoose.model('Order', orderSchema);
order route -
router.post("/", verifyToken, async (req, res) => {
const newOrder = new Order(req.body);
try {
const savedOrder = await newOrder.save();
res.status(200).json(savedOrder);
} catch (err) {
res.status(500).json(err);
}
});
error message when placing order 2nd time__
I think it's happening because backend creates the same document again when the same user places the same order a second time.
So what you can do is create a function in the backend which checks if the user has already ordered the same product then you can just increase the quantity of the product in the document for the same user.
it looks like the problem is that you try to add the same _id twice, in the second time that you want to insert to cart you need to update the order and not make a new one(newOrder.save();)
so before you save new order first check if there is a new order if not make newOrder.save() else you need to )update the cart
if you using mongoose(findOneAndUpdate)
Related
# Norman .. thank you for reply....I am trying hard to know my error.. My code goes link this:
''''
const { body, validationResult } = require("express-validator");
const Customer = require('../models/custdetails');
const async = require('async');
''''
Then I have some code related to sanitization .. then customer object is created
''''
const customer = new Customer({
firm_name : req.body.firm_name,
firm_feature : req.body.firm_feature,
first_name: req.body.first_name,
last_name: req.body.last_name,
mob_no: req.body.mob_no,
cust_email : req.body.cust_email,
date_of_onboard: req.body.date_of_onboard,
date_of_visit: req.body.date_of_visit,
cust_need : req.body.cust_need,
status : req.body.status,
contact_back : req.body.contact_back,
});
''''
here firm feature and cust_need are both arrays, then
''''
const data = req.body;
customer.update({$push: {customer: data},function(err, res){if (err) {
console.log("This is the error while inserting data:", err);
}else {console.log(res); } } });
res.redirect(customer.url);
}
]
''''
My data is not getting inserted into database. I have tried every method. Please help
I have also tried as below
''''
(async function(){
try {
const filter = { first_name: req.body.first_name};
const options = {upsert: true};
const result = await customer.updateOne(filter, {$set:{data}}, options).then(function(){
console.log("data is inserted");
console.log('${result.matchedCount} document(s) matched the filter, updated ${result.modifiedCount} document(s)')
})
}catch(err) {
console.log("Some error has occurred in insertion");
console.log(err);
};
});
res.status(200).redirect(customer.url);
}
''''
Below is my custdetails.js
''''
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CustSchema = new Schema(
{
firm_name:{type: String, maxLength:50},
firm_feature: {type : { type: String }, enum: ['Private Limited Company', 'Public Limited Company',
'Partnerships Company', 'Limited Liability Partnership LLP',
'One Person Company', 'Sole Proprietorship',
'Section 8 Company']},
first_name: {type: String, required: true, maxLength: 100},
last_name: {type: String, required: true, maxLength: 100},
mob_no: {type: Number, required: true, maxLength:10},
cust_email:{type: String, lowercase: true}, //always converts emailto lowercase before saving
date_of_onboard: {type: Date},
date_of_visit: {type: Date},
cust_need: {type : { type: String }, enum:['Four Wheeler Loan', 'Home Loan', 'Two Wheeler Loan']},
brperson: {type: Schema.Types.ObjectId, ref: 'Branch'},
status: {type: Schema.Types.ObjectId, ref: 'CustInstance'},
contact_back: {type: Schema.Types.ObjectId, ref: 'CustInstance' },
}
);
//Export model
module.exports = mongoose.model('Customer', CustSchema);
''''
If you are trying to insert I would switch to "customer.save()" method. Here is an example from my code:
customer.save((err) => {
if (err) { return next(err); }
// Respond to request indicating the user was created
res.status(201).json({ customer: customer }).end();
});
Ultimately, I could save data without array fields getting added, using .save as suggested by Norman and then I $pushed array into the same document by using findOneAndUpdate. I was thinking I could write full data including array fields in one go into the document, but that did not happen...Is this the only answer if I am using node.js, express, mongoose and mongodb?..I dont know. The code goes like this
//First save data without array fields getting saved
customer.save((err) => {
if (err) { return next(err); }
} );
//then save array fields
const filter = { first_name: req.body.first_name};
const options = {upsert: true};
Customer.findOneAndUpdate(filter, {$push: {firm_feature: req.body.firm_feature, cust_need: req.body.cust_need}}, options).then (function(err,res) {
if (err) {
console.log(err);
}else {
console.log("docs inserted");
}
});
In the user model, I have an array of custom objects followedPlaylists which contains two attributes ( playlist: the id of the playlist, public: to determine whether it is public or not) as shown below
const userSchema = new mongoose.Schema({
..... other attributes
followedPlaylists: [{
playlist: {
type: mongoose.Schema.ObjectId,
ref: 'Playlist',
unique: true
},
public: Boolean
}]
})
I want to populate on followedPlaylists.playlist so the response would be something like
[{
playlist: * the actual playlist object *,
public: true
}]
I hope my question is clear enough and thanks in advance.
Here I am assuming that your Playlist is working just fine. i.e., it has elements and has been tested independently.
So, given the schema:
Const Playlist = require (./Playlist)//here you have to provide the path to the Playlist model or use mongoose.model (“Playlist”) to bring it in
………….
const userSchema = new mongoose.Schema({
..... other attributes
followedPlaylists: [{
playlist: {
type: mongoose.Schema.ObjectId,
ref: 'Playlist',
unique: true
},
public: Boolean
}]
})
On whatever you want to print it, just make something like:
Const user = mongoose.model (“User”);//or use require, what fits best your applications
……
Console.log(user.find().populate(“Playlist”))//here is the trick, you ask to populate the Playlist
Example
Examples are the best way to grasp a concept. You can play around with this example:
//------------------------------------------------------------------
const mongoose = require("mongoose");
const { model, Schema } = require("mongoose");
var dbURI = "mongodb://localhost/mongoose-sample";
const app = require("express")();
mongoose
.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(console.log(`connected to ${dbURI}`));
//----------------------------------------------------------------------
const departmentSchema = new Schema({ name: String, location: String });
const Department = model("department", departmentSchema);
const EmployeeSchema = new Schema({
firstName: String,
lastName: String,
department: { type: mongoose.Types.ObjectId, ref: "department" }
});
const Employee = model("employee", EmployeeSchema);
app.use("/", async (req, res) => {
// await Department.remove({});
// await Department.create({
// name: "Fiocruz",
// location: "Presidência"
// }).then(console.log(`we are good`));
// await Department.create({
// name: "IASI",
// location: "Roma"
// }).then(console.log(`we are good`));
// await Employee.create({
// firstName: "Jorge",
// lastName: "Pires",
// department: await Department.findOne({ name: "Fiocruz" })
// });
// await Employee.create({
// firstName: "Marcelo",
// lastName: "Pires",
// department: await Department.findOne({ name: "IASI" })
// });
// Employee.findOne("")
// .populate("department", "name")
// .select("department")
// .then(result => {
// console.log(result);
// });
await Employee.findOne({ _id: "5e6e28ec480a9d32fc78c46b" }, (err, result) => {
console.log(result);
})
.populate("department", "name")
.select("department");
res.json({
departments: await Department.find(),
employees: await Employee.find(),
employeesWithDep: await Employee.find().populate("department", "name"),
justDepartment: await Employee.findOne({ _id: "5e6e28ec480a9d32fc78c46b" })
.populate("department", "name")
.select("department")
});
});
app.listen(3000, () => {
console.log("we are on port 3000");
});
I am trying to make a REST API to handle JSON data from sensors(thermometer, hygrometer) to store and process temperature and humidity data. However at the moment, I am not getting the data directly from sensors yet so I am planning on sending dummy data to the node.js server from a client through http GET/POST requests.
I am using Node.js as a server and I'm trying to save into mongodb using mongoose.
When trying to design this system using mvc design pattern, I was at first trying to only make one sensor.model.js & sensor.controller.js but the problem arose when I had to deal with two different sensor data where each sends its temperature data or humidity data. So I wasn't sure how I should design the API.
I am supposing that it'd be a better option to just POST each sensor data separately to such as "localhost:3000/sensors/thermometer/" and "localhost:3000/sensors/hygromometer/". I can now successfully send POST requests to "localhost:3000/sensors/thermometer/" and "localhost:3000/sensors/hygromometer/" but I want to able to send GET method to fetch all data from '/sensors' sorted by sensor_type. How can I make this possible? Is there any good way to come up with this?
I put codes for sensor.js and thermometer.js below. hydrometer.js is the exact same as thermometer.js so I did not bother to put it.
Thank you so much in advance.
// sensors.model.js
const mongoose = require('mongoose');
const sensorSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
// this method below doesn't work.
sensor_type: {type: String, ref: 'Hygro'},
sensor_type: {type: String, ref: 'Thermo'},
//time : { type : Date, default: Date.now },
temperature: {type: Number},
humidity: {type: Number}
});
module.exports = mongoose.model('Sensor', sensorSchema);
//____________________________________________________________________________
// sensors.route.js
router.get('/', (req, res, next) => {
Sensor.find()
.select('_id sensor_type temperature humidity')
.exec()
.then(docs => {
res.status(200).json({
sensors: docs.map(doc => {
return {
_id: doc._id,
sensor_type: doc.sensor_type,
temperature: doc.temperature,
humidity: doc.humidity + "%"
}
})
});
})
.catch(err => {
res.status(500).json({
error : err
});
});
//___________________________________________________________________________
// thermometer.model.js
const mongoose = require('mongoose');
const thermoSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
sensor_type: {type: String, required: true},
temperature: {type: Number, required: true}
});
module.exports = mongoose.model('Thermo', thermoSchema);
//___________________________________________________________________________
// thermometer.route.js
router.post('/', (req, res, next) => {
// create sensor object
const thermo = new Thermo({
_id: new mongoose.Types.ObjectId(),
sensor_type: req.body.sensor_type,
temperature: req.body.temperature
});
//save thermo obj into the db
thermo
.save()
.then(result => {
console.log(result);
res.status(201).json({
message: 'Created sensor data successfully',
createdSensor_data: {
sensor_type: result.sensor_type,
temperature: result.temperature,
_id: result._id
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
}
Can a sensor store humidity and temperature at the same time?
if not then the design could be simple:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const sensorSchema = new Schema({
_id: Schema.Types.ObjectId,
type: {
type: String,
required: true,
enum: ['Hydro', 'Thermo']
},
//time : { type : Date, default: Date.now },
// for the time I use mongoose built in { timestamps: true }
// temperature: {type: Number},
// humidity: {type: Number}
// store value instead. if it's type 'Hydro' you know it's humidity
value: {
type: Number,
required: true
}
}, { timestamps: true } );
// timestamps: true gives you createdAt and updatedAt automatically
module.exports = mongoose.model('Sensor', sensorSchema);
to get all the sensors
// sensors.route.js
router.get('/', (req, res, next) => {
Sensor.find()
.select()
.exec()
.then(result => {
res.status(200).json({
sensors: result.map(item => {
return item._doc
})
});
})
.catch(err => {
res.status(500).json({
error: err
});
});
})
For post request
router.post('/', (req, res, next) => {
// create sensor object
const sensor = new Sensor({
// _id: new mongoose.Types.ObjectId(),
// you dont new to add _id, Mongoose adds it by default
type: req.body.sensor_type,
value: req.body.temperature
});
//save it
sensor
.save()
.then(result => {
console.log(result);
res.status(201).json({
message: 'Created sensor data successfully',
createdSensor_data: result._doc // you can access the data on the _doc property
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
})
I would also validate req.body for data and throw an error if there isn't any.
I'm developing an app using Node.js, Mongoose, MongoDb, express.
I have 2 schemas one for student and one for snippets. I'm using the population model population model. I can create a user, and create a snippet and link it to the user. But I can't link and save the snippets in the user collection.
How to link and save the user so that it can have a reference to his snippets?
user and snippet schema
var userSchema = Schema({
name: { type: String, required: true, unique: true },
password: { type: String, required: true },
snippet: [{ type: Schema.Types.ObjectId, ref: 'Snippet' }]
})
var snippetSchema = Schema({
user: {type: Schema.Types.ObjectId, ref: 'User'},
title: String,
body: String,
createdAt: {
type: Date,
require: true,
default: Date.now
}
})
This is how I save the snippets I add it inside a user .save() function so that it saves the snippet ref but it gives me user.save() is not a function error.
var name = request.session.name.name
User.find({ name: name }).then(function (user) {
if (user) {
console.log('====================')
console.log(user)
user.save().then(function () { // problem is here?
var newSnippet = new Snippet({
user: user._id,
title: title,
body: snippet
})
newSnippet.save().then(function () {
// Successful
console.log('success')
response.redirect('/')
})
})
}
}).catch(function (error) {
console.log(error.message)
response.redirect('/')
})
But, I actually get the object printed after searching for it!
[ { _id: 5a2e60cf290a976333b19114,
name: 's',
password: '$2a$10$vD3EaQly4Sj5W3d42GcWeODuFhmHCSjfAJ1YTRMiYAcDBuMnPLfp6',
__v: 0,
snippets: [] } ]
You need to use User.findOne to get a valid user object, here you get an array. Also, don't forget to always return something in you promises (or throw an error).
Here is a quick rewrite of your function. With a few improvements such as arrow functions, const and a flat promise chain (never using any .then inside another .then) and avoiding code repetition
const name = request.session.name.name
User.findOne({ name })
.then(user => {
if (user) return user.save()
// What to do if not found? Throw an error?
throw new Error('User not found')
})
.then(() => {
const newSnippet = new Snippet({
user: user._id,
title: title,
body: snippet,
})
return newSnippet.save()
})
.catch((error) => console.log(error.message))
.then(() => response.redirect('/'))
I am creating a webapp using the following stack:
Node
Express
MongoDB
Mongoose
I have structured the app into a MVC structure.
There are Customer, OrderReceived and OrderSent schemas. OrderReceived and OrderSent schema references Customer schema. Abridge schema structures are following:
Customer
const mongoose = require('mongoose');
const customerSchema = mongoose.Schema({
companyName: String,
firstName: { type: String, required: true},
lastName: { type: String, required: true}
});
module.exports = mongoose.model('Customer', customerSchema);
OrderReceived
const mongoose = require('mongoose');
const orderReceivedSchema = mongoose.Schema({
receivedDate: { type: Date, required: true},
customer: {type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true}
});
module.exports = mongoose.model('OrderReceived', orderReceivedSchema);
OrderSent
const mongoose = require('mongoose');
const orderSentSchema = mongoose.Schema({
sentDate: { type: Date, required: true},
customer: {type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true}
});
module.exports = mongoose.model('OrderSent', orderSentSchema);
When a Customer document is asked for delete, I want to check if it the document is referenced by either OrderReceived or OrderSent documents. And if there is a presence I want to prevent the deletion of the Customer document.
The solution I came up with is to do the check in the controller of Customer, as following:
CustomerController#destroy this handles the delete request:
destroy(req, res){
OrderReceived.count({customer: req.params.id}, (error, orderLength)=>{
if (error) res.send(error);
if (orderLength<1){
OrderSent.count({'customer.customer': req.params.id}, (error, orderLength)=>{
if (error) res.send(error);
if (orderLength<1){
Customer.remove({_id: req.params.id}, error => {
if (error) res.send(error);
res.json({message: 'Customer successfully deleted.'});
});
} else {
res.status(409).json({message: 'There are orders sent using the Customer. Datum could not be deleted'});
}
});
} else {
res.status(409).json({message: 'There are orders received using the Customer. Datum could not be deleted.'});
}
});
}
Is there a better way to do this? I have other models that also depends upon the Customer document and this code is only going to get messier.
Please help.
When you are creating OrderReceived or OrderSent save reference of it in Customer too.
So on this way before you delete it, you can simply check if they are empty or not.
Your Customer schema would be like:
const customerSchema = mongoose.Schema({
companyName: String,
firstName: { type: String, required: true},
lastName: { type: String, required: true},
ordersSent: [{type: mongoose.Schema.Types.ObjectId, ref: 'OrderSent'}],
ordersReceived: [{type: mongoose.Schema.Types.ObjectId, ref: 'OrderReceived'}],
});
and your delete function should contain something like:
Customer.findById(req.params.id)
.then(customer => {
if(customer.ordersSent.length== 0&& customer.ordersReceived.length== 0)
return true
//if there was more than 0
return false
}).then(result => {
if(result)
return Customer.findByIdAndRemove(req.params.id)
res.status(409).json({message: 'There are orders received or sent using the Customer. Customer could not be deleted.'})
}).then(customerDataJustInCase =>{
res.status(200).json({message: 'Customer deleted.'})
}).catch(err => {
//your error handler
})
or you can use it via try-catch.
You can use Promise.all method to perform all DB queries at once, like below:
Promise.all([
OrderReceived.count({customer: req.params.id}),
OrderSent.count({'customer.customer': req.params.id})
])
.then(([orderReceivedCount, orderSendCount]) => {
if (orderReceivedCount < 1 && orderSendCount<1) {
...delete doc
}
}).catch(error => ...handleError)