This lesson will walk you through replacing the app's file system reliance with a live MongoDB database. We'll also use a popular ORM library to manage our database operations.
Up to this point, we've just been using the file system for our backing data for our application, but obviously, a more common use case is going to be to use a database. We're going to take a look at how to use MongoDB with your Express app. The first thing that we're going to do is install the MongoDB package from NPM.
This isn't MongoDB itself. It's just a library that'll let us access it from Node. I've also generated a file that we'll use to import the data into the database. You can see it's almost JSON. It doesn't quite fit the format, but the that's the format that MongoDB can import. If we come back to our terminal here, this is now finished installing.
We're going to go ahead and start MongoDB itself, which I've installed previously. That's unrelated to the NPM install. Now, we're going to use a tool that Mongo installs called Mongo Import. We're going to tell it to use the database named Test in the collection named Users. Which, in MongoDB, collections are essentially what you would think of as tables in traditional database.
What you would normally call a row is generally referred to as a document. We're also going to tell it to drop the collection if it needs to and then to use our user list JSON file to get the data. If we run that, we can see that it does drop that collection, and then it imports 30 documents. We've got 30 rows of data in the database.
Let's just go ahead and make everything works. We've got the URI to the database. It's just the standard Mongo port. Then, we're telling it to use the Test database. Then, we're grabbing the Mongo client object off of that MongoDB package. This is the one that we installed through NPM. Then, we're going to jump down here and see.
You call connect. You give it that URI, and then it's going to call your callback once it connects. Once the connection callback is fired, we're going to call this find users function that we have defined, which itself takes the database instance and a callback of its own. In the find users function, we're going to use that database instance.
We're going to say, "We want the users collection, and then we want you to do a find." Then, we're not passing anything into that find method. That just means find everything. That's going to return us a cursor. We're going to iterate over that cursor with the each method, and then pass in a callback to that.
Essentially, if it finds a document, we've got something, and we'll print it out. Otherwise, we're going to call that callback, which eventually just calls close on the database to let it know that we're done. Let's switch over here to our terminal and just go ahead and run this file. We do in fact get a bunch of our user data spit out to the console.
We know that it's working. That's good, but this code is pretty verbose. You can see we've got a lot of callbacks going on. This is just the simplest of use cases to pull out a list of objects from the database. We're actually going to get rid of that, and we're going to use a library called Mongoose.
You can see here that Mongoose is elegant MongoDB object modeling for Node.js. In other words, ORM for Node and MongoDB. I've installed Mongoose from NPM previously. We don't need to look at that. But if we go back to the code, you can see how much simpler things can actually get. First, we need to pull in Mongoose itself.
We need to tell it to connect, using that URI. Then, we're going to get it referenced to its connection and just tell it that once it opens, we're going to log something out to the console. We'll make it a little more helpful here. Then, from there, we can jump straight into the ORM side of things.
The first thing that we're going to do is define a schema. In this case, we've just got a basic user schema here. We've got the username and gender fields. We've got the name object, which I have included that full name property that we were previously calculating, and then the location object, which we use, of course, in our edit form.
Then, what this file's going to export is an object called User, which we're going to get back from calling Mongoose.model. We pass in the name of the model, which is User, and then we pass in that schema that we just defined above. There's one quick thing to note about this name here, is that Mongoose will use that name and lowercase it and make it plural to find the collection.
The fact that we're calling this model User lets Mongo know to use the Users collection. Before we try and integrate that into our application, let's just make sure everything's still working and we've set it up correctly. We're now going to say user.find, going to give it an empty object, because we want everything. Then, we're going to give it a callback.
We'll get the results as the second argument to our callback. You can see that we do, in fact, still get all the data here. It's actually buffered a little bit. We've got our connection to the database working with Mongoose. Let's get rid of this code, and then we'll go connect things in our actual application.
The first thing we'll do is we well pull in this reference to the user object or the user model, I should say, that our DBJS file is exposing. Then, we're going to use that user model in our route handlers. If we come in here to the root handler of the application, we're just going to essentially redo that code we had in the other file and say user.find. Empty object, so we want all of them.
Then, we're going to get the users back from there. We can then grab this render code from up here and actually get rid of all of that. We don't need any of that anymore. We're just going to call a response.render and pass it that Users collection there. If we now go start start our dub server again and go back and check out our application, we can see that we do have our nice list of users again.
We've replaced a good bit of code and a file-system dependency with a two-line structure here, and we're pulling that data out of a live database. Now, let's grab this reference and go ahead...We'll do the same thing in the username file so that we have the reference to that user model. Then, we will update our code that shows our user detail form.
We can get rid of this call to the helper's method that's backed by the file system and replace that, in this case, with a call to user.findone. That's just being explicit and saying we're only expecting one thing to come back here. In this call, instead of passing an empty object, we're going to pass an object that it can use to find that one user.
In this case, we just want it to match that username field with what we've pulled off of the request object. Since our callback defines its payload argument, the second parameter there, as user, we can just go ahead and grab this response.render code, paste it right into our callback, and we're all set. We're going to be referencing that object directly.
Address is still populated correctly. Now, if we go over here and check out a user detail page, it does in fact work. We've now got two pages updated to use our database. You can see that this code is super, super simple.
Let's take a look at how you would use it to edit a record. We're going to say user.findone and update.
Again, this is sort of a single-purpose method that is specifically built for finding and updating a single record or document in your store. We're going to say find the user using that username, but this time, the second parameter is not going to be our callback, but it's going to be an object that can be used to update that object.
The document that gets pulled back is going to be the context, and now we're going to give it an object that it can merge into that document. We're going to say location field should be set to the request.body. It's going to merge that into the user object, and then, finally, we'll give it a callback. We would be getting back that user there.
If we wanted to send it back to the client directly, we could. But since our form already calls reload on the page, we're just going to ahead and end that response there. If we now go back and try and edit this user, we can change their state and hit "Save," and there we go. We've got that data persisted to the database. Just to double, triple check, we'll go and edit another user.
Put Edwin's state back to old Mexico, like it was before. Save that, and now we've got that persisted to the database. You can see how simple this code is and how it takes away a lot of the asynchronicity and specifics of the database system and just allows you to focus on your problem space.