Now with our basic interactions setup, we have to optimize our code a bit and move it into a more realistic
setup.
Now for that more realistic setup, I'll create a new file next to app.js and I'll name it database or
db.js.
Now in this file, I will import mongodb here and then I'll write some code here which gives me a
nice utility script to set up a connection to the database and then get access to the established connection.
For this, I'll
first of all create a new constant,
initDb which simply points at a function which receives a callback,
so another function it can execute as an argument
and here additionally in that file, I'll add a variable with let _db, it has no initial value. Inside
of initDb,
I'll check if db is uninitialized and if it is not uninitialized, so if this returns true which
only happens if it is initialized,
then I'll simply log database is already initialized
and I'll just return my callback,
so I basically call the callback
I basically expect to get a function as an argument so to say and I'll execute that function here and I pass null
as a first argument because my callback will receive an error as a first argument
and I don't want to throw an error here,
it's fine that we already are connected,
so I just return the existing database
but of course this is a case we can't reach right now because we have no code to actually store something
in _db.
So this is what happens now,
I will create my constant mongo client here and use mongodb mongo client to well get access to
the client.
I'll also create a new constant, mongoDbUrl
and that will be my connection
url,
so basically the url I'm using in the products.js file right now here for the connect method.
This string, that is what I copy and that is what I move into the db.js file and which I store here
as a string as about. Now back in initDb,
I will use the mongo client here and call connect and use that mongoDbUrl,
so basically the same code I have in products.js. Now by the way,
you can also, that should have a lowercase l,
you can also pass a second argument where you configure this connection here.
Now this is a bit more advanced and you should check out the official driver docs to learn what you
can configure here,
the default settings should be fine and they are fine for us here.
So I will just connect like this and then here of course, we have a promise then and catch are
therefore functions we can use here. Now in catch, we'll get any error that occurs during the connection
and therefore here in the error case, I will execute my callback and pass that error as the first argument
because I mentioned that the callback, the function I receive here, will be a function I call and I expect
to whoever who passed this function to me to implement this function in a way that it is able to handle
the first argument as a potential error.
So that's the worse, the bad case, the good case is that we are successful so that we do it successfully
connect
and in this case, I get access to the client here in the then block,
so the logic is the same as in the products.js file.
So this client here allows me to then simply store the database,
so db is then equal to client.db,
so this gives me access to the database which was created.
So now I have some method which I can execute to establish a connection,
I'll now create a second constant in the same file which I'll name getDb to get access to this established database
connection,
whoops, it should be written like this, will also be an arrow function
and here I simply return _db.
However first of all, I'll quickly add an
if check, if not _db so
if this is uninitialized, then I'll throw an error where I say database not initialized.
So now I have two functions
in here, initDb to establish a connection and getDb to get access to an existing connection. How
do I use these now?
Well in app.js which is the first file that gets executed when we start up our server,
I can remove that mongodb import I have there and instead, I can add an import to my database
utility file,
so I'll just name it db and I do import my own file by typing require./db and you can omit
the
.js
Now here before I call listen, I will call db
and then what? Well I need to call the functions that are in that file and to make these functions callable,
I add module exports at the end and I'll export an object here and that object will receive initDb
and getDb and this syntax simply creates keys called initDb and getDb which receives their
respective constants which are functions in the end as values.
So now with that in app.js I can call db, initDb
here and initDb needs a callback function
as you learned, a callback function that will either give me an error or the database because here, I want
to also call the callback with null and then the database, like this. And now in
app.js, I know that if I'm in here, I can check if the error exists and if it does, I'll simply console log
the error but else if I got no error, then I can call app listen which starts the nodejs server. So
the nodejs server in this setup here here will start when the connection is established.
Now you can always tweak this but this is a basic setup that ensures that the database is or that our
app here connects to the database at application start up before it starts listening to incoming requests
and then this simply will keep on running. Now in
products.js,
we also don't need the mongo client anymore,
we need mongodb though for the decimal import
but I can now add my own import db by requiring
and now we go up one level with two dots and then we point at db, like this,
so in our db.js file and then in the places where we work with the database, we simply replace this entire
part where we connect and so on
with a call to db, getDb and that returns us the connected database and
therefore this closing pair of brackets can be removed. And now we just interact with the database here
and then the rest of the code stays as it is and in post,
it's the same.
We replace that code here with db, getDb and remove that redundant pair of brackets. With all these
changes, let's quit our currently running backend server, restarting router get catch is not a function,
let's see what's wrong here.
Oh yeah, that catch block here,
that is also redundant now because that was related to catching errors during the establishment of our connection,
we don't need that anymore so let's remove that outer catch block on our get and post route
so that we only have to catch block on forEach or the catch block on insert but not the one that was related
to connecting
and let's now try this again.
This looks better,
we get no error and
if I now reload that front page here, now I have an error,
client is not defined is the error I get here
and that makes sense because I still have the code to close the connection which I don't need to do
and I'll say some words about that in a second too,
so make sure you remove all client close calls here in your products.js file and thereafter, restart.
After reloading, I get a strange result because I accidentally deleted my products constant and therefore,
I load my old products which I have up there. Now I should simply comment out my dummy products up there
which I don't need anymore and then simply recreate my products down there as an empty array to which
I push all the products.
So now with that finally, if we now restart the backend server and we reload that starting page, we should
see only that one product which we added.
So now we have the same functionality as before,
let's also confirm this by adding a new product and for this, I'll just use some of my dummy data,
lovely earrings,
price and the image url here simply
is this url
and then in there, let's also add a description like this.
Now if I create that product, you see the lovely earrings exist here too.
So now we got that all set up,
we're now able to store data, to get data,
now the next step is of course to also get data for a single product
if I click on details here, which right now doesn't work
and I also want to drop some words on reusing that connection which we're currently doing.
I'm using one and the same connection all the time now and this is actually something which you should
do because you'll use a concept called connection pooling which is provided by the mongodb driver
here by default.
That means it actually established a couple of connections or at least it's ready to quickly establish
them and therefore, you can handle multiple incoming requests to your node restAPI
simultanenuously because you can only send one request per connection to mongodb normally
but since you have a connection pool here of multiple available connections, even if you have multiple
incoming connections to nodejs, you can forward them to mongodb
thanks to this connection pooling.
So this is also an advantage of this approach where we reuse one client because here, we actually have
a shared connection pool then.
Now to fully reuse that though, we should not call db here,
so db should just be the client instead and therefore in products.js
when you call getDb, we have to call db ourselves.
So this is one tiny change you should make to be sure you can reuse your connections but with that out
of the way and the backend server restarted one more time, everything should still work right.
So now let's work on getting a single product.