Reputation: 529
I'm building a cinema app. using Node.js and mongodb via mongoose.
When a user makes an order, i need to update the 'Show' model and add the latest seats that was ordered to the 'showTakenSeats' object. note that i need to add the seats to the 'showTakenSeats' and not replace all the object.
The problem is that when i try to update and save the show - everything seems ok. but in the end it does not save it successfully in the DB.
Here is the code:
const express = require('express');
const router = express.Router();
const Order = require('../models/order.js');
const Show = require('../models/show.js');
router.post("/", (req, res) => {
if (!req.body) {
return res.sendStatus(400);
}
let order = new Order(req.body);
order.save().then(newOrder => {
console.log("Order saved successfully");
Show.findById(req.body._ShowId).then(updateShow => {
console.log('we got the show');
console.log(newOrder.ticketsPositions);
console.log("updateShow before any changes");
console.log(updateShow);
newOrder.ticketsPositions.forEach(element => {
updateShow.showTakenSeats[element[0] + "-" + element[1]] = newOrder._id;
});
console.log("updateShow after adding new seats");
console.log(updateShow);
updateShow.save().then((updateShowSaved) => {
console.log('updated the last order seats at the Show seats map')
console.log(updateShowSaved);
//res.json(updateShowSaved);
}, err => {
console.log(err);
//res.send(err);
});
res.json(updateShow);
}, err => {
console.log(err);
});
res.json(newOrder);
}, err => {
res.send(err);
});
});
module.exports = router;
console.log:
Order saved successfully
we got the show
[[6,0],[6,1],[6,2]]
updateShow before any changes
{ _id: 5b5203bfcbb3a311c0911b8f,
_MovieId: 5b45faa4a53b0c05f8959262,
_TheaterId: 5b3dfeb217bc8c23f0e7ec3f,
date: '2018-07-22',
time: '22:00',
dateTime: 2018-07-22T19:00:00.000Z,
showTakenSeats:
{ '0-14': 5b52186a7feaac1028ec592f,
'5-0': 5b530e6dc7d3ed280427145a,
'5-1': 5b530e6dc7d3ed280427145a,
'5-2': 5b530e6dc7d3ed280427145a },
__v: 0,
movieInfo: null,
theaterInfo: null,
id: '5b5203bfcbb3a311c0911b8f' }
updateShow after adding new seats
{ _id: 5b5203bfcbb3a311c0911b8f,
_MovieId: 5b45faa4a53b0c05f8959262,
_TheaterId: 5b3dfeb217bc8c23f0e7ec3f,
date: '2018-07-22',
time: '22:00',
dateTime: 2018-07-22T19:00:00.000Z,
showTakenSeats:
{ '0-14': 5b52186a7feaac1028ec592f,
'5-0': 5b530e6dc7d3ed280427145a,
'5-1': 5b530e6dc7d3ed280427145a,
'5-2': 5b530e6dc7d3ed280427145a,
'6-0': 5b53735ef7ce3d2cd4bbfee7,
'6-1': 5b53735ef7ce3d2cd4bbfee7,
'6-2': 5b53735ef7ce3d2cd4bbfee7 },
__v: 0,
movieInfo: null,
theaterInfo: null,
id: '5b5203bfcbb3a311c0911b8f' }
(node:11476) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.
(node:11476) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
updated the last order seats at the Show seats map
{ _id: 5b5203bfcbb3a311c0911b8f,
_MovieId: 5b45faa4a53b0c05f8959262,
_TheaterId: 5b3dfeb217bc8c23f0e7ec3f,
date: '2018-07-22',
time: '22:00',
dateTime: 2018-07-22T19:00:00.000Z,
showTakenSeats:
{ '0-14': 5b52186a7feaac1028ec592f,
'5-0': 5b530e6dc7d3ed280427145a,
'5-1': 5b530e6dc7d3ed280427145a,
'5-2': 5b530e6dc7d3ed280427145a,
'6-0': 5b53735ef7ce3d2cd4bbfee7,
'6-1': 5b53735ef7ce3d2cd4bbfee7,
'6-2': 5b53735ef7ce3d2cd4bbfee7 },
__v: 0,
movieInfo: null,
theaterInfo: null,
id: '5b5203bfcbb3a311c0911b8f' }
When i check the document in the db after i run the code, The new seats are not being saved in the db.
Anybody knows what the problem?
Thanks
Upvotes: 1
Views: 794
Reputation: 103355
Would consider breaking down the operation into manageable chunks. In this case you'd want to update the showTakenSeats
field with the ticket positions data from the
new order.
Firstly, using async await with your express route you need to save the order and get the created order document. Create a document with the new
taken seats and then update the show document using findByIdAndUpdate
method.
The following example describes the above:
const express = require('express');
const router = express.Router();
const Order = require('../models/order.js');
const Show = require('../models/show.js');
router.post('/', async (req, res, next) => {
try {
/* create a new Order */
const order = new Order(req.body);
const newOrder = await order.save();
/* create a document to use in the update with the following data structure:
{
'showTakenSeats.6-0': 5b53735ef7ce3d2cd4bbfee7,
'showTakenSeats.6-1': 5b53735ef7ce3d2cd4bbfee7,
'showTakenSeats.6-2': 5b53735ef7ce3d2cd4bbfee7
}
Use the native reduce method on the array to create this
*/
const updatedSeats = newOrder.ticketPositions.reduce((acc, position) => {
acc[`showTakenSeats.${position.join('-')}`] = newOrder._id;
return acc;
}, {});
/* update the show document's embedded showTakenSeats
with the new properties from above
*/
const updateShow = await Show.findByIdAndUpdate(req.body._ShowId,
{ '$set': updatedSeats },
{ 'new': true }
);
res.json(updateShow);
} catch (e) {
/* this will eventually be handled by your error handling middleware */
next(e);
}
});
Upvotes: 2
Reputation: 2790
It looks like you think that the function executes in a sequential order, but when you call .then
on a promise like updateShow.save().then
the execution of the function doesn't wait and continues! This causes the error message below where you try to set the headers
after they already have been sent:
> (node:11476) UnhandledPromiseRejectionWarning: Unhandled promise > rejection (rejection id: 1): Error: Can't set headers after they are > sent. (node:11476) [DEP0018] DeprecationWarning: Unhandled promise > rejections are deprecated. In the future, promise rejections that are > not handled will terminate the Node.js process with a non-zero exit > code.
You can make your function async
and await
function calls to finish work before continuing.
Example:
router.post("/", async (req, res) => {
let order = new Order(req.body);
await order.save(); // if this fails an exception is thrown
console.log('order is saved') // statement is executed after order is saved
}
More on async
and await
:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
This is possibly not the only bug in your code and therefore this will not answer your question but this text is too long for a comment.
Upvotes: 1