Managing Orders with Mongoose | Creating a REST API with Node.js
- January 3, 2024
- Posted by: MainInstructor
- Category: Go JavaScript Node
Video Title: Managing Orders with Mongoose | Creating a REST API with Node.js
Welcome to another video in this series where we build a restful api with nodejs the previous videos we had a look at how we work on our products and how we store products in the database and that’s all working now when I work on the orders and the interesting part here of course
Is that orders are connected to products so let’s dive into that in this video so let’s start working on that and the first thing I want to do is I want to create a model for my orders so I ordered J’s file now copy the logic from
The product JS file to import non-use and export a model at the end though the schema will be named order schema and I’ll name the model order – now how should that look like do I want to have an ID and whatever unique ID per order I also need one important piece of
Information I need to know which product was ordered now you could of course create a way more complex setup where you have carts so shopping carts which comprise a couple of our products and quantities I want to start and stick simple here I want to say okay I got an order and that
Order is connected to one product which I ordered so how does this work then I’ll add a product key and I’ll set this equal to an object now the type here will actually also be an object ID because I will store the ID of the product which is related to this order
Now there’s something important we’re now creating like a relation and MongoDB is a non relational database you can kind of rebuild these relations as we’re about to do that and that is okay to some degree but if you find yourself building a lot of relations and sticking
Very much in that sequel database world then you might indeed wanna pick a sequel database because you might not need the advantages of a no sequel database like MongoDB but you will just get all the disadvantages if you work with a lot of relations now this one relation here that’s perfectly fine but
I just want to bring this to your attention so let’s set up the relation here then and as I said first of all let’s assign you type to be an object ID and then there’s an important keyword ref you need to use ref here to configure this
Type and ref should now hold a string with the name of the model you want to connect this model to know if we have a look at our product JS file we see that the name is product so it’s this name we assigned here and that’s the name I now
Always use here I want to connect this schema with my product and with that I store my order where I say we ordered this product now let’s say a product or excuse me an order also knows a quantity here we could set a type to be number
And we can set required to true because I want to have a quantity on each order you could of course also make this optional and you could also say okay I might not require it I’ll just set a default which is one that’s also an option now just required and default
Together don’t make a lot of sense but in this case you’re saying you don’t need to pass me a quantity if you pass me nothing I’ll use that default of one so we’ll always store a quantity in the database it’s just going to be our default quantity if no data there are no
Additional information is passed and that is a very simple order look at the product we got the quantity the price as part of the product so we can calculate the total price and with that we got a schema setup for orders now let’s use that scheme and our order J’s file
Before we fetch all orders let’s work on hosting them now for that I’ll import two things I’ll import Mongoose to create an ID so I’ll simply require Mongoose here and I will of course also import my order model from the models file and there from the order J’s file
With there we can create a new order so I’ll create an order but I’ll treat it differently with new order so using our model as a constructor which we can of course and then passing a JavaScript object where we will configure it now I’ll set the ID equal to Mongoose types
Object ID executed as a function to automatically generate an idea then I can set the quantity to request body quantity though that might not be sad sodas might be null but it should still work we’ll see if it does and I also need to set my product and now this
Needs to be the idea of the product we’re connected to and I expect to get this a request body product ID maybe this also means that back in the order model we probably want to set this to be required so that we can’t pass null here
So back here in our order J’s file the routes file we’re now creating our order or storing it in the database where we’re trying we’re setting it up we cannot store it by a chaining save and then on save we can chain then or actually we can’t chain exit to turn it
Into a real promise then and catch are also provided on the return values by default but that’s they’re not a real problems with the ex ecute is so now we can add them and catch and then we can use the result we’re getting back here
You may be log it to the console and of course to also resend a status code of 201 where we essentially for now send a simple results but response we’re going to find you this where a just return the result and when we catch an error I’m
Going to console lock that error here and I’m going to return a response with status code 500 where I send an error or property that holds the error we got and I’ll remove the default damage response we used previously let’s find out if that works now for that let’s go back
And let’s first of all get the list of products and restart our server first of all so let’s get a list of products maybe this one with that ID let’s copy the ID let’s create a new post request which targets slash orders to send a post
To that endpoint not send a JSON body which should be a normal JSON object where I do set you know this is important where I do set quantity and product ID so I’ll add product ID as a key here and past the idea just copied
And I’ll set quantity as a key here and set this to two now if I had sent or I get an error accident work yeah true we’re saving here so generally that was true exit gives you a real promise whereas normal queries and save is not a curious
This but queries we’re used find for example these give you back a Venn method but no catch method and then you can use X Act to turn it into a real promise for save you actually get a real promise by default so that out of the
Way let’s try that again now here we see we created a new object with its own ID which is different to the Product ID of course we store it the product ID and we got the quantity of two now let’s all try not passing a quantity if I now hit
Send we see we also get this default quantity of 1 and if I now don’t send an ID so I don’t send anything we get an error that the product is required which makes sense so now we can successfully create new orders let’s make sure we can
Also view all orders by going to our general get route here and let’s use order here together with fine with no arguments to find all orders if you pass an argument to find it would be an object that describes the object you want to find just as we use the for
Update and delete but here I want to find all orders and I simply will execute X X to again turn it into a real promise here and then chain then and catch and then let’s see what we can do here let’s use all the docs we get back
And for now simply return them with a status code of 200 Jason Docs like that and for an error I will send a status code of 500 where I said Jason to an object were we store and return the error now if dad’s setup let’s save this and let’s
Try it out by sending a get request to orders like this for hit Send here I get all the orders I did create so the two with quantity two I stored and the one with quantity one so this is now my get request now let’s already work on the response
Layout so here for example I don’t want to return that the part and I want to return more information than just the array of items so I’ll add select prior to exit and just select the product and the quantity field and the ID let’s say and then again here I’ll return an
Object where I have count which is Doc’s length and where I then also have my orders which is now docks and where I have my request object let’s say with a type of get because I also want to support details on our individual order so get to a URL which would be HTTP
Localhost 3,000 orders slash and then it would be our ID of that document now to get this back I made a mistake of course shouldn’t return orders like this I should map it here to get the individual doc and then return a new object here for that document we got
Where I then have my ID that a stock underscore ID where I have my product that is dark Product ID so just excuse me just product what we got here suggest product and when we didn’t got the quantity which is stock quantity and where we then pass our request object
And where we now can use dark underscore ID like this now if we save this we get the same logic as an hour product routes I get this more structured response with more information the same makes sense for creating a new object here if we succeeded I might want to return a
Message where I say order stored and where I then pass a URL where you can get more information like the type here you could then set the type to get and the URL would essentially be the same as we use up here so I can just copy that
URL down to this return a response here access it on the result I get this is the object that was created and of course also maybe have a created order object here that holds the information about the created order and there we could output the ID from result ID the
Product from result product and of course the quantity from result quantity and if we tried that out by creating a new order by sending a post request to orders with the body we used before but maybe with a valid product ID so let’s reuse that product ID we already used in
The past if you do it like this product ID should be the key name here then we store this and we see that nice a response by the way if we pass an invalid ID for a product doesn’t exist we also store debt so this also works
Now we’re storing a bunch of orders on products that don’t actually exist in the database so that is something we’ll have to make sure that it doesn’t happen so let’s turn or let’s add some logic to control this we want to make sure that we can’t create new orders for products
For products we don’t have so here in our post method in the orders J’s file now first of all check if we actually do have a product for a given ID now to do that I’ll import product here by calling required and going to the models folder and then the product file
And then I can use a static method on product here call find PID and search for a request body Product ID and now what I can do is if this succeeds then I want to continue with creating the order otherwise I want to return an error here
I will simply return a response with status code 500 where I return an object where I say message product not found and as always you could all return some machine readable error code here and pass the detailed error object now in the Dan block here I’ll actually get my
Product or my document but it is a product let’s knit maybe name it like this and then in here I can execute the average code here to store that new to store it that new order however now we have a nice level of nesting which we don’t want when using promises so what
We can do is I can simply return orders safe which does return a promise as you see and then I can use that the ban and the catch blocks and chain them after here just means that this catch block here isn’t too useful anymore because it’ll never execute because we have this
Outer catch block here so now with that we got a set up where I check if we do have a product before I then try to save it and we then execute all the our steps for creating the order and for it returning a response and if we don’t
Have our product here well then we’ll get into disk catch block where we return the error anyways so now with that if we save this and we try again to create a product which has an invalid ID it still succeeds do you know why well remember what we did in that products jeaious
File there we also check we do find a product here but we check this in a success case because remember if you pass an ID for which no product is found then you don’t get an error you just get null for product in this case so actually we want to check that
If product if not product which means if it’s knowledge then we want to return the response where we set the status code to 404 and where we then can return our response where we may be say message product not found and yeah that’s it and since I returned all subsequent code
Won’t be executed in this case now with dad if I send this now I get product not found here and with that again if I do get all my products and I dare for fetch a valid ID of a product and I now create a post request to orders again and I do
Use such a valid ID it again succeeds so this works but we can’t store orders for products we don’t have which of course is very useful now let’s continue let’s get information about the individual order well there we can’t just use product excuse me not product order and
Call find by ID and pass request parents order ID as an argument because we named it order ID here call X sector turn it into a real promise and then use catch and then again and here we’ll get our document you couldn’t alter name it order because
It is an order whatever you want and you can return a response with status code 200 and then there a JSON object where again we can pass our information about the object we got so there we could now return order and that is equal to the order argument we get
Here from Mongoose and add our request metadata object where we can say yeah you can course send us a get request maybe to the following URL to get all requests so the URL would be H via local host 3000 slash orders to get all the orders and
That’s just one example we could use as always and that here in the error case I want to return a response with status killed 500 where we use Jason to of course all returned an object where I as always wrap this error in my error property now with that finally for all
Let’s try it out I guess so let’s first of all copy that order ID we have here and let’s try a get request to this order ID and there we go now we also get that link to fetch all orders we can click on that and we see all the
Orders we created quite a bit so time for a delete function and let’s work on that delete function here there again I can use order and then remove and pass an object to identify what I want to remove I want to remove that object that has an ID that matches my request
Parents order ID property because again I named it order ID here and then I can chain x”k then and catch and a so often in catch I just want to return my error so I’m going to copy that code and you could of course also outsource this into
Some general function you then always call that returns this response and in the Dan block I want to return a response so I get my result here won’t return a response where I essentially have a message that could be order deleted and the request could suggest to
Create a new order by posting to orders and there we needed to send an object a body where we will pass the product ID which will be an ID whatever type you want to describe here and then quantity which is a number something like that now if we do that let’s again
Get all orders because we certainly have too many and then let’s fetch one of the orders maybe this one and let’s now try sending a delete request to this endpoint if I do that the order was deleted indeed and if I try to get information for that order it fails
Orders now because we don’t find it now that of course means that in our get requests here where we find by ID I should also add a if check if not order so if it’s null as is in the example I just ran was then I probably want to
Return a response where I set the status code to 404 and return an object where I say message order not found so that I avoid having cases like this where I get order now which you could use if that’s your requirement but I don’t want it now
If I try to fetch details for an order that doesn’t exist I get a 404 error and that again was a lot of work but now we worked on the orders side queue we’re storing that relation now querying this relation and in general now working with
All that data and seeing how we can further evolve our restful api is what we’ll dive into next
-
Sale!
Wireless WIFI Repeater Extender Amplifier Booster 300Mbps
$29.99$14.99 Add to cartWireless WIFI Repeater Extender Amplifier Booster 300Mbps
Categories: Electronics, Wi-Fi Router, Wireless Wi-Fi Extender Tags: 300Mbps, 802.11N, Amplifier, Booster, Extender, mobile wi-fi booster, Remote, WIFI, Wireless, Wireless WIFI, Wireless WIFI Repeater, Wireless WIFI Repeater Extender, Wireless WIFI Repeater Extender Amplifier, Wireless WIFI Repeater Extender Amplifier Booster, Wireless WIFI Repeater Extender Amplifier Booster 300Mbps$29.99$14.99 -
Sale!
Full RGB Light Design Gaming Headset Headphones with Mic
$24.99$14.99 Add to cartFull RGB Light Design Gaming Headset Headphones with Mic
Categories: Electronics, Gaming, Gaming Headsets Tags: Design, Full, Full RGB Light Design Gaming Headset, Full RGB Light Design Gaming Headset Headphones, Full RGB Light Design Gaming Headset Headphones with Mic, Gamer, Gaming, Gaming Headset Headphones, gaming headset wireless, Headphone, Headphones, Headset, Light, Mic, Package, RGB$24.99$14.99 -
Sale!
Wireless BlueTooth Multi-Device Keyboard Mouse Combo
$39.99$19.99 Add to cartWireless BlueTooth Multi-Device Keyboard Mouse Combo
Categories: Electronics, Gaming, Gaming Keyboards, Keyboard Mouse Combos Tags: Combo, Keyboard, keyboard mouse combos, Mouse, MultiDevice, Set, WireKeyboard Mouse Combo, Wireless, Wireless BlueTooth Keyboard Mouse Combo, Wireless BlueTooth Keyboard Mouse Combos, Wireless BlueTooth Multi-Device Keyboard Mouse Combo, Wireless BlueTooth Multi-Device Keyboard Mouse Combos$39.99$19.99 -
Sale!
High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar
$199.99$139.99 Add to cartHigh Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar
Categories: Gaming, Gaming Chairs Tags: Adjustable, Chair, computer chairs, Desk, Executive, Gaming, Girl, Headrest, High, High Back Leather Executive Adjustable Swivel Gaming Chair, High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest, High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar, High Back Leather Executive Adjustable Swivel Gaming Chairs, Leather, Lumbar, Office, Racing, Swivel$199.99$139.99 -
Sale!
Professional LED Light Wired Gaming Headphones with Noise Cancelling Microphone
$29.99$19.99 Select optionsProfessional LED Light Wired Gaming Headphones with Noise Cancelling Microphone
SKU: N/A Categories: Electronics, Gaming, Gaming Headsets Tags: Cancelling, Gaming, Gaming Headphones with Noise Cancelling Microphone, gaming headset, Headphones, Headset, LED, Light, Mic, Microphone, Noise, Professional, Professional LED Light Wired Gaming Headphones, Professional LED Light Wired Gaming Headphones with Noise Cancelling Microphone, Wired, Wired Gaming Headphones, Wired Gaming Headphones with Noise Cancelling Microphone$29.99$19.99 -
Sale!
Gaming Desk with LED Lights USB Power Outlets and Charging Ports
$349.99$249.99 Select optionsGaming Desk with LED Lights USB Power Outlets and Charging Ports
SKU: N/A Categories: Computer Desk, Gaming, Gaming Desk Tags: and Charging Ports, Charging, Desk, Desks, Gaming, gaming desk with led lights, Gaming Desks with LED Lights, Home, LED, Lights, Monitor, Office, Outlets, Port, Power, Room, Stand, USB, USB Power Outlets, White, Workstation$349.99$249.99 -
Sale!
Wired Mixed Backlit Anti-Ghosting Gaming Keyboard
$99.99$79.99 Add to cartWired Mixed Backlit Anti-Ghosting Gaming Keyboard
Categories: Electronics, Gaming, Gaming Keyboards Tags: Antighosting, Backlit, Blue, brown, Gaming, Gaming Keyboard, gaming keyboards, gaming keyboards and mouse, Keyboard, Laptop, Switch, Wired, Wired Mixed Backlit Anti-Ghosting Gaming Keyboard, Wired Mixed Backlit Anti-Ghosting Gaming Keyboards, Wired Mixed Backlit Gaming Keyboard$99.99$79.99 -
Sale!
Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset
$119.99$59.99 Add to cartWireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset
Categories: Electronics, Gaming, Gaming Headsets Tags: 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset, ANC, Audio, Bluetooth, Cancellation, Ear, Earphone, gaming headset, Headphones, Headset, Hi-Res Over the Ear Headphones Headset, HiRes, Noise, Wireless, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Headphones, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headsets$119.99$59.99 -
Sale!
Wired Sports Gaming Headset Earbuds with Microphone
$19.99$9.99 Select optionsWired Sports Gaming Headset Earbuds with Microphone
SKU: N/A Categories: Gaming, Gaming Headsets Tags: Accessories, Earbud, Earphone, Earphones, Gaming, gaming headset with microphone, Headphones, Headset, IOS, Microphone, Sports, Wired, Wired Sports Gaming Headset Earbuds, Wired Sports Gaming Headset Earbuds with Microphone, Wired Sports Headset Earbuds$19.99$9.99 -
Sale!
150W Universal Multi USB Fast Charger 16 Port MAX Charging Station
$49.99$29.99 Add to cart150W Universal Multi USB Fast Charger 16 Port MAX Charging Station
Categories: Charging Stations, Electronics Tags: 150W, 150W Charging Station, 150W Universal Multi USB Charging Station, 150W Universal Multi USB Fast Charger 16 Port MAX Charging Station, 150W Universal Multi USB Fast Charger 16 Port MAX Charging Stations, 150W Universal Multi USB MAX Charging Station, 16 Port MAX Charging Station, 3.5A, Charger, Charging, Fast, laptop charging stations, Max, Multi, Port, Stand, Station, Universal, USB$49.99$29.99
I think you lost a lot of people at 15:00 when you cut and pasted some of the code. It wasn't exactly very visible what you were doing!
for any future watchers, if you're getting the error "product: ValidatorError: Path `product` is required." at around 8:00 when attempting to create the order, make sure you're setting the content-type in postman to JSON.
thank you teacher for share education for everyone
You can avoid this error – Error [ERR_HTTP_HEADERS_SENT]: – by replacing the return statement with: throw 'Product not found';
for those getting this error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
Try this code:
router.post("/", (req, res, next) => {
Product.findById(req.body.productId)
.then(product => {
if (product) {
const order = new Order({
_id: mongoose.Types.ObjectId(),
quantity: req.body.quantity,
product: req.body.productId
});
order.save().then(result => {
console.log(result);
res.status(201).json({
message: "Order stored",
createdOrder: {
_id: result._id,
product: result.product,
quantity: result.quantity
},
request: {
type: "GET",
url: "http://localhost:3000/orders/" + result._id
}
});
}).catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
}
else{
return res.status(404).json({
message: "Product not found"
});
}
})
});
a solution for the then block which is not passed
router.post("/", async (req, res, next) => {
const productFound = await Product.findById(req.body.productId);
if (!productFound) {
return res.status(404).json({
message: "Product not found"
})
}
const order = new Order({
productId: req.body.productId,
quantity: req.body.quantity
})
const createdOrder = await order.save();
console.log(createdOrder);
if (createdOrder) {
res.status(201).json({
message: "Order stored",
createdOrder: {
_id: createdOrder._id,
productId: createdOrder.productId,
quantity: createdOrder.quantity
},
request: {
type: "GET",
url: "http://localhost:3000/orders/" + createdOrder._id
}
})
} else {
res.status(500).json({ message:"Some error occured" })
}
})
Your videos are really nice, this is how we learners expect to be explained.
I want to ask that in order schema if i want to add the user detail(like the users id,name,address,phone,email) what i need to do?
16:49: I think there is a bug here. I've just tested and seen that even if "return" is used, the code WOULD NOT stop executing there, which means the 2nd then() block will still be run no matter what the result of the "Product.findById" is.
It's because there is no exception triggered in the first then() block (just the doc is not found) so the code will keep going down to the next then() instead of exiting.
So when the 2nd then() block is run, the response would be sent again by this code "res.status(201).json(…)" and as a result "cannot set headers after they are sent to the client" exception will be thrown.
For the error:
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
Try with async-await:
router.post('/', async (req, res, next) => {
try {
const productFound = await Product.findById(req.body.productId).exec();
if (!productFound) {
return res.status(404).json({
message: "product not found"
})
}
const creatredProduct = new Product({
// …
});
const documentCreated = await creatredProduct.save();
console.log('Create document', documentCreated);
const response = {
message: 'Created asset successfully',
// …
};
res.status(201).json(response);
} catch (err) {
res.status(500).json({error: err.message});
}
});
As displayed on the console, the error description is:
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch()
Max, still very spot on. Like the way you guys work at academind. Very good way to start this old dog learning new things after years of not programming at all. Clear tutorial. Thx.
Thank you for such wonderful contents for free!
Is this a bug?
in the POST route, there are 2 then promise after Product.findById(req.body.product_id):
the first promise returns "Product not found" and the second promise is executed too.
check this out:
// ===== Test =====
const promise1 = new Promise((resolve, reject) => {
resolve('Success!');
});
promise1.then((value) => {
console.log("==== then 1 ====")
return 0
})
.then(value => {
console.log("==== then 2 ====")
});
// ___ Test ___
// ====== output =====
==== then 1 ====
==== then 2 ====
Great lectures buddy 👍🏻
you can create same video mysql node js express same product(add,delete,edit,list),order(add,delete,edit,list), validation , join to table order and product and login ,registration authtoken routers all 14 video please created
Awesome video!
How system will automatically detect product: productID in 5:16
I think use async/await along with try/catch would be better in configuring route
Can you make a video using MySQL instead of MongoDB?
Anyone gets the same result as mine with .delete() method? If I try to delete the order that was already deleted, I get the result with "DeleteCount: 0". Mongoose kind of putting deleted item in the cache or something. So it remembers the deleted items. So if I delete the order with the same id multiple time, it doesn't show "invalid id". Also, in there is message in the console telling me that .remove is deprecated and suggest that .deleteOne, .deleteMany, and .bulkwrite should be used instead.
Does anyone did order.js in es6 method.
I am continuously gett error validation error , product path required in postman
When entering invalid productId that doesn't exist in products, has anyone observed that some ids return `Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters`?
what is the Builder utility you are using @7:30
Error: Order validation failed: product: Path `product` is required.
i keep getting this error at 8:00, and i havent a clue how to solve it, can anyone help
Error: Order validation failed: product: Path `product` is required.
how sir changed all occurence at.048