Skip to content

1. Introduction

In Express.js, a model typically represents the data layer in an MVC (Model-View-Controller) architecture. The model is responsible for interacting with the database, performing CRUD (Create, Read, Update, Delete) operations, and returning the data that will be used by the controllers to serve responses to the client.

1. What is a Model in Express.js?

  • Model: Represents the data structure of the application and interacts with the database. The model defines how data is structured, validated, and stored in the database.
  • Express is primarily a server-side framework and does not come with a built-in ORM (Object-Relational Mapping), so you typically use an external ORM like Mongoose for MongoDB, or Sequelize for SQL databases.

2. Setting up Express.js

Here’s how to set up a simple Express application with MongoDB and Mongoose (as the ORM for MongoDB) for a model.

Steps:

  1. Install Express.js, Mongoose, and other dependencies:

    Terminal window
    npm init -y
    npm install express mongoose
  2. Create the main app file (app.js or server.js):

    const express = require('express');
    const mongoose = require('mongoose');
    const app = express();
    const port = 3000;
    // Connect to MongoDB
    mongoose.connect('mongodb://localhost:27017/expressdb')
    .then(() => console.log('Connected to MongoDB'))
    .catch(err => console.log('Error connecting to MongoDB:', err));
    app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
    });

3. Using a Database with Express Models (MongoDB + Mongoose)

In a MongoDB environment, you typically use Mongoose to define your models.

Example:

Let’s build a User Model as an example.

  1. Install Mongoose (if not installed already):

    Terminal window
    npm install mongoose
  2. Create a models/user.js file:

    const mongoose = require('mongoose');
    // Define schema for User
    const userSchema = new mongoose.Schema({
    name: {
    type: String,
    required: true,
    },
    email: {
    type: String,
    required: true,
    unique: true,
    },
    password: {
    type: String,
    required: true,
    },
    createdAt: {
    type: Date,
    default: Date.now,
    },
    });
    // Create User model
    const User = mongoose.model('User', userSchema);
    module.exports = User;

4. Building a Basic Model

A model in Express.js defines the structure of your data, interacts with the database, and provides functions to create, read, update, and delete data.

In the example above, we created a User model using Mongoose, which:

  • Defines fields (name, email, password, etc.).
  • Specifies validation rules (e.g., required, unique).
  • Uses a schema to structure how the data will be stored.

5. CRUD Operations with Models

Here’s how to implement basic CRUD operations for the User model.

Create a User (POST Request):

const express = require('express');
const User = require('./models/user');
const app = express();
app.use(express.json()); // For parsing application/json
// POST route to create a new user
app.post('/users', async (req, res) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).json(user);
} catch (err) {
res.status(400).json({ message: err.message });
}
});

Read Users (GET Request):

// GET route to fetch all users
app.get('/users', async (req, res) => {
try {
const users = await User.find();
res.json(users);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
// GET route to fetch a single user by ID
app.get('/users/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) return res.status(404).json({ message: 'User not found' });
res.json(user);
} catch (err) {
res.status(500).json({ message: err.message });
}
});

Update User (PUT Request):

// PUT route to update user details
app.put('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
if (!user) return res.status(404).json({ message: 'User not found' });
res.json(user);
} catch (err) {
res.status(400).json({ message: err.message });
}
});

Delete User (DELETE Request):

// DELETE route to delete a user
app.delete('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) return res.status(404).json({ message: 'User not found' });
res.json({ message: 'User deleted successfully' });
} catch (err) {
res.status(500).json({ message: err.message });
}
});

6. Validations and Middleware in Models

You can add validation to your schema fields to enforce rules for data consistency.

Example of Adding Validation to the Model:

const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
validate: {
validator: function (v) {
return /\S+@\S+\.\S+/.test(v);
},
message: props => `${props.value} is not a valid email!`,
},
},
password: {
type: String,
required: true,
minlength: [6, 'Password must be at least 6 characters'],
},
});

Example of Middleware (Pre-Save Hook):

You can also add middleware (like pre-save hooks) to handle certain actions before saving to the database. For instance, you might want to hash the password before saving the user:

const bcrypt = require('bcryptjs');
// Pre-save hook to hash password
userSchema.pre('save', async function (next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 10);
next();
});

7. Model Associations (Relationships)

If you need to relate multiple models (e.g., one-to-many or many-to-many), you can use references or embedded documents.

Example of One-to-Many Relationship (User to Posts):

You can relate a User to multiple Posts using references in Mongoose.

  1. Post Model (models/post.js):

    const mongoose = require('mongoose');
    const postSchema = new mongoose.Schema({
    title: {
    type: String,
    required: true,
    },
    content: {
    type: String,
    required: true,
    },
    author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    },
    createdAt: {
    type: Date,
    default: Date.now,
    },
    });
    const Post = mongoose.model('Post', postSchema);
    module.exports = Post;
  2. Using the Relationship:

    • To create a post with a reference to a user:
      const user = await User.findOne({ email: 'example@example.com' });
      const post = new Post({
      title: 'My First Post',
      content: 'This is the content.',
      author: user._id,
      });
      await post.save();
  3. Populating the Reference:

    • You can use Mongoose’s populate method to fetch related data:
      const posts = await Post.find().populate('author', 'name email');