so I've recently tried to create a booking site in which you can select a date you wish to book. Then you'd send a request to /api/v1/reserve which would check if the data is valid. Generate a stripe payment intent, save the reservation to the database and send the payment intent id to the front end (for confirmation). My problem is that if two clients click send at the same time, they both pay for the same date which shouldn't happen.
router.post("/reservation", async (req, res) => {
//Check if everything is in the reqest
if (!req.body?.name || !req.body?.phone || !req.body?.date) return res.sendStatus(400);
if (!req.body.phone.match(/^[+]{0,1}[4]{1,2}[8][\s0-9]*$/)) return res.status(400).json({
type: ErrorTypes.PHONE
});
//Validating date
const reservationDate = new Date(req.body.date);
if (reservationDate < new Date()) return res.status(400).json({
type: ErrorTypes.DATE
});
//Checking if date is already reserved
if (await checkIfDateReserved(reservationDate)) return res.status(400).json({
type: ErrorTypes.RESERVED
})
//if reservation date is weekend raise the price
const estimatedPrice = reservationDate.getDay() == 6 || reservationDate.getDay() == 0 ? 3500 : 2000;
try {
//Create payment intet
const intent = await stripe.paymentIntents.create({
amount: estimatedPrice,
currency: "PLN",
payment_method_types: ['card']
});
const document = new ReservationModel({
name: req.body.name,
reservationDate: reservationDate,
phone: req.body.phone,
complete: false,
intentId: intent.id
});
await document.save();
//If everything went smoothley, send the secret to the client
//Send the client the intent secret to confirm the payment
res.json({ clientSecret: intent.client_secret });
} catch (error) {
res.status(500);
}
});
Basically, both processes run in parallel in different threads and they check if the date is reserved at the same time and reserve it at the same time. How can I make it so the database will wait until the first save request is finished before processing another? The reservationDate field is unique but it seems MongoDB still ignores it.
PS: Also, I thought about using transactions but I don't really know how would they apply here.