MongoDB and Mongoose | Creating a REST API with Node.js

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to this video now over the last videos of this series we already added quite some functionality to our node restful services we added our first routes for products and orders but we don't really work with the data we get we don't really manage the data we have no database we're going to change this in this video we're going to add MongoDB as a database and Mongoose as a package to work with that database to store data get data and so on so let's dive into that so as I said I'll be using MongoDB you could also use a sequel based database and you can always search for sequel vs no sequel to find a lot of discussions up about when to choose which I'll go with MongoDB here I might add sequel as a bonus later in a series but we'll see and for that I simply google for MongoDB to end up on MongoDB com now there we could simply download MongoDB so if you click on solutions here you can simply click on try it now MongoDB 3.6 you can download it and stall it on your machines set it up connect to it on your machine you can do all that I'll use MongoDB Atlas though now what is a MongoDB Atlas it's simply a MongoDB database in the cloud managed by the company behind MongoDB and we can't get started with that for free why am i using that because if we think to the end we obviously want to deploy our API at some point and building a really scalable MongoDB on your own so a cluster of databases replicating data and all that stuff is something you probably don't want to do on your own now MongoDB Atlas does all of that for you it's a database as a service and you can work with it just as you work with it or with you as you work with the local long going to be you can install and you can get started for free behind the scenes is hosted on AWS and as I said you don't have to pay to get started so you can simply choose a region here now I'll pick an American one North Virginia and then if you choose m0 as a size so regarding the power you have available and so on you see it doesn't cost anything now you can of course pick a paid one for real applications but for playing around I'll use debt now you can see you don't need a credit card to get started so let's just get started I'm quickly going to fill this out here once you did sign up you can choose their name for your cluster I'm going to name this node rest shop because that's what we're building here you can choose whatever you you can choose someone going to be version though here it basically I'll stick to the default here the cloud provider so there you could also switch to a different one but I'll stick to AWS the region you want to use on the provider and then important make sure to select the free tier so the hourly cost should switch to zero dollars so make sure that this is selected you don't accidentally pick a paid one if you don't want that these are all shared clusters which might not be the best choice for running it in production but for development that's great and then down there do you want a Charlotte cluster we don't want to take all of that you can enable backup but it'll cost man money thereafter you'll need to create an admin username and password so it'll quickly do that obviously you want to choose a more secure combination and I did here and then you can click confirm and deploy now let's quickly confirm that we're not a robot and this will set up this MongoDB cluster for us though here we really will only have one instance we'll take a little time and once it's done we'll get the connection details that allow us to use it in our node application to connect to it so even though we're developing the node restful service on our local machine we can of course connect to this MongoDB running in the cloud and again if you feel totally uncomfortable using that or you don't want to use it for some reason you can always install one way to be locally and then use that local address that's perfectly fine too now let's do some useful stuff whilst is working and let's click on secure it here there you see the users you created you can all do whitelist IP so I peace that may access this instance here and I simply clicked add Kurt IP address to add my well Kurt at your IP address or allow access from anywhere so that of course might not be what you want you might not want everyone to be able to access this so choose whichever setup you want I'll use that doubt you also be able to access this again once my IP address changed and with that setup let's go back to overview and you that's not finished yet it is here for me though you can click on connect here and connect your application and there you will find the URL you'll basically need to use to connect your application to your instance here you can click copy here to simply copy that and we'll need this in our node.js app we'll also need to replace the password and with that we could see what they suggest us as drivers here for a note for example they suggest your official client but I'm going to use Mongoose which is a different package that makes working with data with schemas fetching and storing data super simple so I won't use their official client I'll use Mongoose which will build up on this client so let's leave this page for now and let's go back to our code there I'll quit the server and install a new package with NPM install - - save then Mongoose that's the package name and - - save also creates an entry in the package JSON file now with that finished you can now obviously start using it and I will start using it in the app J's fall where I want to set up a connection now I will connect to my database here in the app.js file where we start our application for that all first of all import Mongoose here by simply adding require Mongoose like that and then here I'll call Mongoose connect and now to connect I first of all need to pass a path and here I'll passed path I copied from our MongoDB Atlas page I dare now also need to replace the password which in my case also is node shop and typically you might want to put this into some environment variable so that here you actually access something like process thought and thought atlas password whenever you chose as an environment variable name and then you could set this up on the server you're deploying this to so that you don't have to hard coded here into your code now it used it with node one on the add a new fall file node montage Jason which I can use to configure it and there I will simply add an end key for environment variables which is an object and there we can now define all the environment variables we want to use like for example here Atlas PW so I'll add this here as a name and the value will be the password we chose on Atlas with that we should be able to get this dynamically and we don't have to hard-coded in our code now add a second argument to disconnect function and object where I will set use client to true so that under the hood it will use the MongoDB client for connecting which is the recommended way for using mongoose when using manga version 4.3 do on our atlas which is the recommended way of using this when using mongoose version 4 or higher which we do as you can see here now if that let's try it out and for that let's go to the routes file and then let's say for products when we post a new product with the name and a price let's say we want to store that in the database now to do that I will use Mongoose and for that I'll first of all need a mongoose model because mongoose and there's no in-depth mongoose course or video but mongoose works with models and schemas so you define how objects you store in the database should look like and then you create a model based on that which is just a javascript object to put it simple and then this model will have a couple of functions you can use to save data update data fetch data by ID by our criteria order it merge different data sets and so on so that's what mongoose offers do for you and it can always recommend checking out the official talks to which you'll find a link in the video description so I'll add a models folder in the API folder and there are now add a product or JS file to define how a product should look like in my application for Dettol first of all import Mongoose here to in store in a constant named Mongoose so in that and you file and then I'll create such a schema I'll create a new constant here and I'll name it product schema the name is up to you and I will use Mongoose an unknown goose the schema method here essentially to which I pass a JavaScript object which defines how my product should look like now my product should have an ID and I'll use underscore idea which is kind of a convention which will be of type that is how you could figure it the value here is the type of data this will be which will be of type Mongoose types and then object ID that's a special type which is essentially a serial ID not a number but simply a long string and that's a specific format Mongoose uses internally which we assigns the type here then let's say a product should have a name and that will just be a string so we can use the string type like this with a capital S then we also want to have a price which should be a number and that is actually all I want now we'll export this schema wrapped into a model though so a schema is like the layout that the sign of the object you wanna use the model then is the object itself or gives you a constructor to build such objects based on that schema you could say so I'll set up module exports here and that is equal to Mongoose model and now that model function takes two arguments the first is the name of the model is you want to use it internally and name this product the convention here is to use an upper case starting character and then the second argument is this schema you want to use for that model with that we get our product model setup we can now use new products J's file in the routing folder for that I'll import my product here with capital key here to as a constant name and I'll import it from my model file and they're from the product file of course that is what we just defined it now here in post I can use it to store data for that I'll first of all trade a new instance of that models a new product lowercase P maybe where I use new and then my model as a constructor now to that constructor I pass a JavaScript object where I passed data for that model and there I'll need to set an ID because we defined that we want to have a D here and I will import Mongoose for that with require Mongoose to be able to create a new object ID here new Mongoose types and now object ID as a function constructor function essentially will give me a new ID will automatically create one for me and that will be a unique ID which I can't get twice then I'll add a name here of course and that name will be a request body name and I'll set a price my request body price that of course means we can remove the old product we created here now we got a product object which is actually created with the help of Mongoose and that's a special object where I then call it can call product safe so save as a method provided by Mongoose which I can use on Mongoose models save will then store this in the database now I can chain a method here x'q which essentially will turn this into a promise if I don't call that I would have to pass a callback here an arrow function where I either have an error or the result of that operation which I of course can do but I didn't want to use a callback here I want to use a promise so I'll chain them here and in there I will get back the result of that operation which I'll lock to the console so result and I also want catch potential errors sort of all the chain catch here where I get the error which I did also want to log to the console like that so this is how I try to save that to the database now let's save that and let's rerun NPM start to run note 1 again and I get an error here you see that I got undefined object ID in my schema file so let's have a look at what's going wrong there the problem I have here is I use this a bit incorrectly this Mongoose type object at the ISTE constructor function which I correctly use here in products J s here to create the ID now to just tell Mongoose that I want to use this type I don't use that constructor function of course instead I have to access Mongoose schema.org IDs or density correct type with that if I save this and then I quit this server and restart it now I should run without errors and does and now let's try sending a post request to slash products which should trigger this route for that I'm back in postman all target products here and I will attach a body to my request of course not product ID in quantity but instead a name so here I will use Harry Potter 5 and you can of course also use other products and the price which all set to $12.99 now let me click send here and I get unexpected end of JSON year because I mistakenly removed that closing parenthesis here so let's send us again and I indeed get back a response here create a product and this of course here is the data created by Mongoose because we're returning the product which is our Mongoose object so we're getting back the data which was safe to the database hopefully now if we have a look at our log we also see this log here which is looking good now on longer DB Atlas it can take some time until see it if that really succeeded here in your dashboard because right now it hasn't it isn't showing data up to the point of time when we really wrote this eventually you should see that you performed one right action here but we can simply check by always returning that data if we access a certain Product ID so for the get route of products here I can of course also get this product with this ID for that I will remove my dummy code here and instead I want to use this product model and that's the object I'm importing here at the top because I don't need to create a new one here instead I'll use a static method on that object which is called find by ID and it does what the name suggests now I pass the ID to that and call X SEC and then I can call them and catch now let me restructure this over multiple lines now and then I clearly want to get my document and here I'll simply log it to the console for now and then catch I obviously want to get any errors I might face so here I'll console.log an error now right now I'm not sending a response anymore though and I want to send a response once we got the data so I don't want to call res status and so on after the catch block because since promises run asynchronously this would simply mean that I run the code immediately before that response is there because code which I write into this line here will not wait for all that code to finish so instead I want to send a response from inside the den block when I know that it was successful or also from inside the catch block but there I want to send an error so here in the den block I'll use rest status 200 and I will send back JSON data of course and let's simply sent back to talk as we get it so I'll just set doc here as an argument now in the catch block I as a just set wanna actually do more than just logging this to the console I also want to send a response there the status code will be 500 though because something failed whilst fetching the data and I'll set a JSON response where I will add an error property which is equal to the error I'm catching here with that if we save that file let's try it out let's copy that ID we got when we created the object and let's target product slash dead IT ID with a get request now then let's click send and I do get back this response really quick and this does look very promising because to me that really looks like we successfully fetched the data we changed it here and we can also see that we really have this data from the database by adding from database here so we're not seeing some old version of our code if I click send again we still get the data and in the log we see from database so this really is our update code fetching the data from the database and eventually you now see one connection at least here on your Atlas dashboard if you refresh and wait a bit you will also eventually see the reads and writes you're having on that so we're storing the data in the database we're getting it from the database now one thing we can improve is in the post request right now I sent my response immediately I don't wait for this operation to succeed or fail so just like for getting the data I want to put my success response inside the success callback and I will return the result we get here and for the error case here I also still want to lock the error here for us but I also want to send a different response here with a 500 error code where I said Jason or where a sent data in JSON format where I also have an error property which holds the error we actually got so that if something failed we really see that here too now let's also try a invalid ID so I'm get requests for iid I removed the C which doesn't exist by now Santa's you see we get an error and there we see that this couldn't be cast to you an object ID because it's actually not just an ID which doesn't exist it's an invalid object ID and that's detected by Mongoose if I add a D which now is a valid object ID by the one which doesn't exist I simply get back null because that doesn't throw an error and it shouldn't it's not an error it's just that we don't have data for that ID so we probably in our get function wanna check for the duck if the doc is there so if it's not null then I want to send a response with the doc me document in the our case I probably want to send a response which is 404 where I have a JSON object where maybe I have a message no valid entry found for provided ID or something like that so that now if I save this we actually have different kinds of answers we can return we get a 404 answer you can see the status code here with our error message if I enter invalid ID if I enter a valid one with a see at the end I do get a 200 response and if I do enter an invalid object ID then I get by 500 response my 500 error so this is how we can work with MongoDB and Mongoose now we're fetching an individual product and we're fetching or we're storing a product now of course we also have our general get method where I want to return all products we have so let's also take care about this for this I'll again use my product object up here and now we can't just use find and if I don't pass an argument it will find all elements now you can also add more query operators here like for example you can add where to add more conditions to that query or you add limit to only fetch a smaller number and you could manually implement some form of pagination then here I'll fetch all for now though I'll call access to get a true promise and then chain catch and and then restructure it over multiple lines and in the den block I'll have all my documents so all my products and I want to return them and there I simply want to console log all Doc's and then for now return in a response with status code 200 where I simply return the docs as JSON data and I'll also catch any errors we might get here where I will console lock the error for us here and we're out there after simply return a status code of 500 with an object where I have my error again provided to our front end now if I save this let's try a general get request targeted at products if I sent this we get back an array with this one object in there so with this one product that's great of course that's coming directly from the database now before we continue working on this get requests and before we check which our response you might return in the van block if we haven't any data in the database let's make sure that we can't encounter the case of not having any data there by adding the delete functionality now so there I will now also use product so this model object and there I can now access remove and to remove I pass an object which describes the object I want to remove and I don't have to pass all properties I don't have a have to pass an exact copy of the object I want to remove but the filter criteria and I'll use the ID for that and the idea is something I can get from my URL so I'll store the new constant pain tidy and I get it from request parents Product ID and that of course is just Product ID because that's the name I chose here so now I'll assign value here and this essentially means remove any objects in the database that fulfill this criteria so that have an ID property which has the value of this idea and we should only have one object dead works like this or that fulfills this criteria then I'll execute exit to get a real promise and I'll chain then and catch now and that as always and then I get some result which I can console lock but I'll here immediately return it set the status code to 200 and simply return result maybe let's name it result should not get into conflicts with the response variable we're using here and in the catch block I'll possibly get an error which I'll log to the console but where I then also want to return a response with status code 500 where I pass an object which has an error property that then in turn contains that error object we got from Mongoose now let's save this and now if we grab that ID from the object we got and we add a T at the end of our URL we can get the data for that single object but if we now switch this to a delete request and click send I get this answer which I guess means that it worked it's some data about the process was executed let's simply try by fetching all products again with a get request and we get an empty array so we successfully deleted the data object that also means something else we get an empty array and not null here that's important for our get method here for our get route here when we fetch Doc's we return an empty array maybe we want to do that but we could also check if Doc's length is greater or equal than 0 if it is then I want to return my response like this else I want to return 404 response and now this is really something you can think about because you could also argue that it's not really a 404 error if we got no data here so we'll remove this in a second but I want to show that you could use this piece of information and there you could set up an object you returned with a message no entries found now again this is something you can use but I'll remove that entire check here I'll comment it out because I think it's not really an error if we got no entries in there it's not really like we didn't find a resource as it is if we try to query an ID that doesn't exist here we just want to fetch all products and it turns out that we got none but that's not an error at least in my opinion so I'll leave the setup we had but you could use that information that the docs here will be an empty array and not null for this check to return some other response if you want it so with that there is one method we have populated and that is incoming patch requests where we want to change our our object where we want to change data in the database now let's also work on that to finish up that product setup here now updating is simple with Mongoose we can again use our product model and then there is an update method now to that method we first of all need to pass an identifier for the object we want update just as we had to for delete for move so I'll extract the ID from product IDs from my URL and I'll pass the same argument as I passed to remove I want to update an object that fulfills this criteria that has an ID that matches this ID then however I also want to change something about that object now the second argument describes how we want to update this this is also a JavaScript object and there we can use a special property name dollar sign set which is understood my Mongoose so this is not an arbitrary name you have to use dollar signs set here to then pass another object as a value to that where you then describe key value pairs on how to update your object so for our product which has a name and a prize and an ID but we don't want to change that that's the idea behind patching we want to keep the existing object and just change some properties but if we change the ID we essentially have the same as if we would have created a new object so we want to change name and/or price so here what I'll do is I will set name to request and now I expect to get this on the body so request body new name maybe and the price to request body new price this of course assumes that we always pass both to our endpoint and the idea behind patches that we don't have to do that maybe we want to just update the price or just update the name so we should check if we really do want to update both so for that let's add some other check first I'll create a new constant which we'll name update ops for update operations which is an empty JavaScript object and then I'll trade a loop here where I'll loop through all the operations of my request body so I expect my request body to essentially be an array here now with that I can use update ops and add a new property with that syntax here where I can use Ops prop name because I expect to pass this and you will see the other side of how we pass the data so that here will be something like name or price and I'll set it equal to ops value this will give us an object that in the end will have this form but only with the operations I want to perform so here I can now set update ops and this will be an object which might have no key value pairs if we somehow sent a patch request without a payload then it shouldn't change anything we might just change the name or just change the price and with this dynamic approach we're making sure that we can really send different types of patch requests with that I can as always chain xx to get a promise and hence chain catch and then thereafter and and then I'll get the result which I here wants to log again and where I don't want to return and let's again use result here and then I'll again use response status with a code of two hundred and Jason data which is sent back where I will simply pass the result back to the user and in catch I'll get a console log where I lock the error and then I return the status killed five hundred with why Jason payload where I have my error property where I returned the error to the user with that if we save that file let's try it out and let's see what happens if we try to patch an object for that I'll first of all trade a new one so I'll post two products and set my object here quickly run a get request fine so that's stored let's fetch the ID and then I'll create a patch request here now for patch I'll add the ID to the URL but then I'll also provide a body where I will set the name to Harry Potter six now if I send sent is I get request body is not iterable because my request body here clearly is still an object and remember I wanted to use a different approach I wanted to get an array where in the array we have objects that have things like prop name and value so let's do that I'll actually pass an array here as a payload which I can do that's all the valid JSON and then I could have multiple objects here and I'll have a prop name property in here should be between quotation marks though because we're writing jason here and the value here will be name because i want to adjust the name property in my data and then i'll also have a value property which holds the new value which now is harry potter six so now if i send this we get back status code okay now let's see if that really works by going back to a get request and getting the data and indeed you see the name is Harry Potter six the price wasn't touched though and if I go back and again patch a request and this time I want to set the price and set it to let's say 14.10 if I sent this also get back this script egg response but if I now get the data for this product we indeed see the price was adjusted the name is the same now if I go back one more time and I patch a new party where I want to set price new which is a property we don't define our schema and I said this back now I get back a different response and if I get the data for this object you see this wasn't added so I can't add new properties like this I can really just change existing ones I can't add new ones and this is of course on purpose I don't want to be able to add new ones like this we obviously could rewrite this to allow the addition of new properties but I really want you work with a set of properties that's known in advance where I can't add new ones and that was quite some talking and work about setting everything up setting up moong or at last connecting Mongoose using Mongoose creating a schema and model but now we get a first draft of how the products routes could work and and look like if we really use a database obviously this is not final we might need more fields than just as a name in a price but it's nice to get started and we already achieved something very important we got a first version of the restful api where we actually persist our data in a database and work with that so let's continue on the road and let's see which our cool things we can add to this API
Info
Channel: Academind
Views: 377,345
Rating: undefined out of 5
Keywords: node, rest, restful, rest api, mongo, mongodb, mongoose, tutorial
Id: WDrU305J1yw
Channel Id: undefined
Length: 36min 3sec (2163 seconds)
Published: Tue Dec 12 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.