[Database][Sequelize] Sequelize 관계 정리

JIEUM KIM·2025년 4월 24일

Database

목록 보기
6/9

Node.js 환경에서 백엔드 개발을 하다 보면 데이터 간의 관계를 표현해야 할 상황이 자주 발생한다. 예를 들어, 사용자(User)가 여러 개의 일기(Diary)를 작성하고, 각 일기에는 댓글(Comment)이나 좋아요(Like) 같은 상호작용이 추가되는 구조는 매우 흔하다. Sequelize는 이러한 관계를 쉽게 정의하고 활용할 수 있도록 도와주는 ORM(Object-Relational Mapping) 도구이다. SQL 쿼리를 직접 작성하지 않고도 모델 간 관계를 설정하고, 그 관계를 기반으로 데이터를 효율적으로 다룰 수 있게 해준다.

이번 포스팅에서는 Sequelize에서 제공하는 주요 관계 메서드를 정리하고, 각 메서드가 어떤 상황에서 어떻게 사용되는지 예제와 함께 알아보자.


📌 Sequelize 모델 관계란?

Sequelize는 Node.js 환경에서 널리 사용되는 ORM(Object-Relational Mapping) 라이브러리로, 객체 지향 방식으로 데이터베이스를 다룰 수 있도록 도와준다. Sequelize를 사용하면 각 테이블을 모델로 정의하고, 이 모델들 간의 관계를 설정하여 보다 직관적으로 데이터를 관리할 수 있다.

현실 세계의 데이터는 서로 연결되어 있는 경우가 많기 때문에, 모델 간의 관계를 명확하게 설정하는것은 중요하다.

✏️ ORM이란?

ORM(Object-Relational Mapping)은 객체 지향 프로그래밍 언어와 관계형 데이터베이스 사이의 불일치를 해소해주는 기술이다. 쉽게 말해, 코드에서는 객체(Object)로 데이터를 다루고, 실제 데이터는 테이블(Table) 형태로 저장되는 구조를 연결해주는 역할을 한다.

ORM을 사용하면 SQL문을 직접 작성하지 않고도 JavaScript 문법으로 데이터를 생성, 조회, 수정, 삭제할 수 있어 개발 생산성과 유지보수성이 향상된다.


✏️ 외래키(Foreign Key) 개념 간단 설명

외래키는 하나의 테이블이 다른 테이블을 참조할 수 있게 해주는 키이다. 즉, 한 테이블의 컬럼이 다른 테이블의 기본키를 참조함으로써 두 테이블 간의 관계를 연결해준다.

예를 들어, Diary 테이블의 user_id 컬럼은 User 테이블의 id 값을 참조한다. 이를 통해 "이 일기를 누가 작성했는가?"라는 질문에 대해 쉽게 답할 수 있으며, User와 Diary 간의 1:N 관계를 설정할 수 있게 된다.


📌 Sequelize 관계 메서드

✏️ hasOne

hasOne은 1:1 관계를 정의할 때 사용한다. 한 모델이 다른 모델의 단 하나의 인스턴스와만 연결될 때 적합하다.

예를 들어, 사용자가 하나의 프로필을 가질 수 있는 구조에서 사용된다.

User.hasOne(Profile);
Profile.belongsTo(User);

여기서 외래키는 Profile 모델에 생성되며, user_id와 같은 형태로 저장된다.


✏️ hasMany

hasMany는 1:N 관계에서 사용된다. 하나의 모델이 다른 모델의 여러 인스턴스를 소유할 수 있는 구조이다.

가장 흔한 예로는 사용자(User)가 여러 개의 일기(Diary)를 작성하는 구조가 있다.

User.hasMany(Diary);
Diary.belongsTo(User);

이 경우 외래키는 Diary 테이블에 생성되며, 해당 사용자의 ID를 참조하게된다.


✏️ belongsTo

belongsTohasOne 또는 hasMany와 반대 방향의 관계를 정의한다. 이 메서드는 외래키가 현재 모델 안에 있을 때 사용한다.

예를 들어, Diary가 User에 속해 있다는 관계를 명시하고 싶을 때 다음과 같이 작성한다.

Diary.belongsTo(User);

belongsTo는 언제나 외래키가 자기 자신 안에 있는 경우에 사용한다는 것이 핵심이다.


✏️ belongsToMany

belongsToMany는 다대다(N:M) 관계를 정의할 때 사용한다. 이 관계는 중간 테이블을 통해 두 모델이 서로 여러 개의 인스턴스를 가질 수 있을 때 설정된다.

예를들어, 사용자가 여러 동아리에 가입할 수 있고, 하나의 동아리에 여러 사용자가 가입할 수 있는 구조에서는 중간 테이블은 UserClub과 같은 테이블이 필요하다.

User.belongsToMany(Club, { through: 'UserClub' });
Club.belongsToMany(User, { through: 'UserClub' });

중간 테이블에는 두 외래키(user_id, club_id)가 들어가며, 이를 통해 다대다 연결을 관리할 수 있다.


✏️ 깔끔 정리 !

메서드관계 형태외래키 위치사용 예시
hasOne1:1대상 테이블User → Profile
hasMany1:N대상 테이블User → Diary
belongsToN:1자기 자신Diary → User
belongsToManyN:M중간 테이블User ↔ Club (UserClub)

📌 관계 설정에서 유용한 옵션들

Sequelize에서 모델 간의 관계를 정의할 때는 기본적인 메서드 외에도 다양한 옵션을 함께 설정할 수 있다. 이 옵션들은 관계의 의미를 더 명확히 하거나, 데이터 무결성과 유지보수를 용이하게 만들어주는 역할을 한다.

✏️ as - 별칭

as옵션은 관계에 별칭을 지정할때 사용한다. 동일한 모델 간에 여러 관계가 존재하거나, 보다 직관적인 이름을 설정하고자 할때 사용된다.

User.hasMany(Diary, { as: 'diaries' });

위와 같이 설정하면, 사용자 인스턴스를 통해 user.getDiaries()같은 메서드로 연관된 데이터를 조회할 수 있다. 별칭을 지정하면 .include()나 .getXXX() 등의 함수에서 해당 이름을 사용해야 한다.


✏️ foreignKey - 외래키 이름 설정

foreignKey 옵션을 사용하면 Sequelize가 자동으로 생성하는 외래키 이름 대신, 직접 외래키 이름을 지정할 수 있다.

User.belongsToMany(Club, { through: 'UserClub' });
Club.belongsToMany(User, { through: 'UserClub' });

이렇게 설정하면 Diary 테이블에 userId 대신 author_id라는 컬럼이 외래키로 생성된다.


✏️ through - 중간 테이블 지정

`belongsToMany`관계를 사용할 때는 **중간 테이블**이 필요하다. 이 중간 테이블을 명시하려면 `through`옵션을 사용한다.
User.belongsToMany(Club, { through: 'UserClub' });
Club.belongsToMany(User, { through: 'UserClub' });

여기서 userClub은 두 모델 사이의 관계를 연결해주는 테이블이다. 이 테이블에는 보통 두 외래키(user_id, club_id)가 포함되며, 관계를 기록하거나 추가적인 정보(예: 가입일)를 함께 저장할 수 있다.


✏️ onDelete, onUpdate - 데이터 연쇄 처리

관계된 데이터가 삭제되거나 수정될 때, 그에 따라 연쇄적으로 처리되는 동작을 지정할 수 있다. 대표적으로 CASCADE, SET NULL, RESTRICT 등이 있다.

User.hasMany(Diary, {
  onDelete: 'CASCADE',
  onUpdate: 'CASCADE'
});
  • CASCADE : 부모 데이터가 삭제되면, 자식 데이터도 함께 삭제된다.

  • SET NULL : 부모 데이터가 삭제되면, 외래키가 NULL로 설정된다.

  • RESTRICT : 참조 중인 데이터가 있을 경우 삭제/수정이 제한된다.


0개의 댓글