Building a Node.js Application with Sequelize, PostgreSQL, and HasOne, BelongsTo, HasMany Association

In this tutorial, we'll create a Node.js application using Sequelize as the ORM, PostgreSQL as the database, and demonstrate how to define and use a hasOne association between two models: User and Address.


Prerequisites

Before we start, ensure you have the following installed:

  1. Node.js and npm.
  2. PostgreSQL installed and running.

Step 1: Setting Up the Project

Initialize a new Node.js project:

mkdir sequelize-postgres-example
cd sequelize-postgres-example
npm init -y

Install the required dependencies:

npm install express sequelize pg pg-hstore
npm install --save-dev sequelize-cli

Step 2: Initialize Sequelize

Initialize Sequelize in your project:

npx sequelize-cli init

This command generates the following directory structure:

project/
├── config/
│   └── config.json
├── migrations/
├── models/
│   └── index.js
├── seeders/
└── package.json

Configure the database connection in config/config.json:

{
  "development": {
    "username": "your_username",
    "password": "your_password",
    "database": "sequelize_example",
    "host": "127.0.0.1",
    "dialect": "postgres"
  }
}

Create the database:

createdb sequelize_example

Step 3: Create Models

We'll create two models: User and Address. The User model will have a hasOne association with the Address model.

Generate the Models

Run the following commands:

npx sequelize-cli model:generate --name User --attributes name:string,email:string
npx sequelize-cli model:generate --name Address --attributes street:string,city:string,userId:integer

Step 4: Define the hasOne Association

Edit the generated models in the models folder.

models/user.js

'use strict';
const { Model } = require('sequelize');

module.exports = (sequelize, DataTypes) => {
  class User extends Model {
    static associate(models) {
      // Define a hasOne association with Address
      User.hasOne(models.Address, { foreignKey: 'userId', as: 'address' });
    }
  }
  User.init(
    {
      name: DataTypes.STRING,
      email: DataTypes.STRING,
    },
    { sequelize, modelName: 'User' }
  );
  return User;
};

models/address.js

'use strict';
const { Model } = require('sequelize');

module.exports = (sequelize, DataTypes) => {
  class Address extends Model {
    static associate(models) {
      // Define a belongsTo association with User
      Address.belongsTo(models.User, { foreignKey: 'userId', as: 'user' });
    }
  }
  Address.init(
    {
      street: DataTypes.STRING,
      city: DataTypes.STRING,
      userId: DataTypes.INTEGER,
    },
    { sequelize, modelName: 'Address' }
  );
  return Address;
};

Step 5: Sync Database

Run migrations to create the tables in your PostgreSQL database:

npx sequelize-cli db:migrate

Step 6: Seed Some Data

We’ll create seeders to populate the database with sample data.

Generate Seeders

npx sequelize-cli seed:generate --name demo-user

Edit the Seeder (seeders/{timestamp}-demo-user.js)

'use strict';

module.exports = {
  async up(queryInterface, Sequelize) {
    const userId = await queryInterface.bulkInsert(
      'Users',
      [
        {
          name: 'John Doe',
          email: 'john.doe@example.com',
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ],
      { returning: true }
    );

    await queryInterface.bulkInsert('Addresses', [
      {
        street: '123 Main St',
        city: 'Sample City',
        userId: userId[0].id,
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    ]);
  },

  async down(queryInterface, Sequelize) {
    await queryInterface.bulkDelete('Addresses', null, {});
    await queryInterface.bulkDelete('Users', null, {});
  },
};

Run the seeders:

npx sequelize-cli db:seed:all

Step 7: Query Data

Let’s write a small Express application to fetch users along with their addresses.

Create app.js

const express = require('express');
const db = require('./models');

const app = express();
app.use(express.json());

app.get('/users', async (req, res) => {
  try {
    const users = await db.User.findAll({
      include: [{ model: db.Address, as: 'address' }],
    });
    res.json(users);
  } catch (error) {
    console.error(error);
    res.status(500).send('Server Error');
  }
});

app.listen(3000, async () => {
  await db.sequelize.authenticate();
  console.log('Server is running on http://localhost:3000');
});

Step 8: Test the Application

Start the server:

node app.js

Access the endpoint:

  • Open your browser or use Postman to visit: http://localhost:3000/users

Response:

[
  {
    "id": 1,
    "name": "John Doe",
    "email": "john.doe@example.com",
    "createdAt": "2024-11-23T12:34:56.789Z",
    "updatedAt": "2024-11-23T12:34:56.789Z",
    "address": {
      "id": 1,
      "street": "123 Main St",
      "city": "Sample City",
      "userId": 1,
      "createdAt": "2024-11-23T12:34:56.789Z",
      "updatedAt": "2024-11-23T12:34:56.789Z"
    }
  }
]

Conclusion

You’ve successfully built a Node.js application with Sequelize and PostgreSQL, defined a hasOne association, and queried related data. This approach is scalable and can be extended to handle more complex relationships in your application.

Related Posts