MongoDB with Express.Js

MongoDB with Express.Js

Eventually every Node.js project running wwith Express.js as web application will need a database. Since most server applications are stateless, in order to scale them horizontally with multiple server instances, ther is no way to persist data without another third-party (e.g database). That's why it is fine to develop an initial application with sample data, where it is possible to read and write data without a database, but at some point you want to introduce a database to manage the data. The database would keep the data persistence across servers or even though one of your servers in not running.

The following section will show you how to connect your Express application to a MongoDb databse with Mongoose as ORM. If you havn't installed MongoDB for your machine. It comes with a MacOD and Windows setup guid. Afterward come back to the next section of this guid to learn more about using MongoDB in Express.

MONGODB WITH MONGOOSE IN EXPRESS INSTALLATION

To connect MongoDB to your express application, we will use an ORM to convert information from the database to a JavaScript applciation without SQL statements. ORM is short for Object Related Mapping, a technique that programmers use to convert data among incompatible types. More specifically, ORMs mimic the actual database so a developer can operate within a programming language (e.g JavaScript) without using a database query language to interact with the database. The downside is the extra code abstraction, that's why there are developers who advocate against an ORM, but this shouldn't be a problem for many javaScript applications without complex database queries.

for this application, we'll use Mongoose as ORM. Mongoose provides a comfortable API to work with MongoDB database from steup to execution. Before you can implement database usage in your Node.js applicatin, install mongoose on the command line for your Node.js application:

npm install mongoose --save

After you have installed the library as node packages, we'kk plan and implement our databse enities with modles and schemas.

DATABASE MODELS, SCHEMAS AND ENTITIES

The following case implements a database for your application with two database entities: User and Message. Often a database entity is called database schema or database model as well. You can distinguish them the following way:

Database Schema: A database schema is close to the implementation details and tells the database (and developer) how an entity (e.g user entity) looks like in a database table whereas every instance of an entity is represented by a table row. For instance, the schema defines fields(e.g username) and relationships (e.g a user has messages) of an entoty. Each firld is represented as column in the database. Basically a schema is the blueprint for an entity.

Database Model: A database model is a more abstract perspective on the schema. It offers the developer a conceptual framework onwhat models arre available and how to use models as interfaces to connect an application to a database to interact with the entities. Iften models are implemented with ORMs.

Database Entity: Adatabse entity is actual instance of a stored item in the database that is created with a database schema. Each database entity uses a row on the database table whereas each field of the entity is defined by a column. A relationship to another entity and ends up as field in the database as well.

Before diving into code for your applicatin, it's always a good idea to map the relationshpis between entities and how to handle the data that must pass between them. A UML(Unified Modeling language) diagram is a straightforward way to express relationships between entities in a way that can be refeerence d quickly as you type them out. This is useful for the personlaying the groundwork for an applicaiton as well as anyone who wants to additoinal infromation inthe database schema to it An UML diagram could appear as such:

uml.webp

The User and Message entities have fields that define both their identity within the construct and their relationships to each other. Let's get back to our Express application. Ususlly, there is a folder in your Node.js applcation called src/models/ that contains files for model in your database. Each model is implemented as a schema that defines the fields and relationships. Ther is often also a file that combines all models and exports all them as database interface to the Express application. we can start with the two models in the src/models/[modelname].js fiels, which could be expressed like the following without covering all the fields from the UML diagram for the sake of keeping it simple. First, the user in the src/models/user.js file:

const mongoose = require('mongoose')
const userSchema = new mongoose.Schema(
   {
      username: {
         type: String,
         unique: true,
         required: true
      }
    },
    { timestamps: true }
)
const User = mongoose.model('User', userSchema)
export default User

As you can see, ther user has a ussername fiels which is represented as string type. In addtion, we added some more validation for our user entity. First, we don't want to ahve duplicated to the field. And second, we want to make the username string required, so that there is no user without a username. Last but not least, we defined timestamps for this database entity, which will result in additional createdAt and updateAt fields.

We can also implement additional methods on our model. let's assume our user entity ends up with an email field inthe future. Then we could add a method that finds user by their an abstract "login" term, which is the username or email in the end, in the database. That's helpful when users are able to login to your applcation via username or email address. You can implement it as method for your your model. After, this mothod would be available next to all other build-in methods that come from your chosen ORM:

userSchma.statics.findByLogin = async (login) => {
   let user = await this.findOne({
      username: login
   })
}

This message model looks quits similar, even though we don't add any custom mrthods to it and the fields are pretty straightforworward with only a text field:

const mongoose =  require('mongoose')
const messageSchema = new mongoose.Schema(
{
   text: {type: String, required: true}
}
{timestamps: true}  
)
const Message = mpngoose.model('Meaasge', messageSchema)
export default Message

However, we may want to associate the message with a user:

user: {tyep: mongoose.Schema.Types.ObjectID, ref: 'User'}