[PostgreSQL] Polymorphic Association

1 minute read

Polymorphic Association

  • Definition
  • Solution1
  • Solution2
  • Solution3

Definition

  • 모델이 하나 이상의 모델과 관련될 수 있는 경우
  • 예를 들어, 인스타그램에 대한 DB를 만들고 ‘좋아요’에 대한 정보를 저장해야할 때, 게시글에 대해서, 그리고 댓글에 대해서 좋아요를 할 수 있음

Solution1

  • liked_type column을 통해 post인지, comment인지 구분하도록 함
  • 장점: 확장성의 측면에서 좋음
  • 단점: liked_id는 FK가 될 수 없음(한 COLUMN이 comments, posts의 두개의 테이블과 연관이 있으므로)
CREATE TABLE comments (
	id SERIAL PRIMARY KEY,
	contents VARCHAR(240) NOT NULL
);

CREATE TABLE posts (
	id SERIAL PRIMARY KEY,
	url VARCHAR(200) NOT NULL
);

CREATE TABLE likes (
	id SERIAL PRIMARY KEY,
	user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  -- FK to posts & comments's id
	liked_id INTEGER NOT NULL,
	comment_id INTEGER REFERENCES comments(id) ON DELETE CASCADE,
  -- 'post' or 'comment
  liked_type VARCHAR(20)
);

Solution2

  • comment와 posts와 연결되는 FK를 각각 만들기
  • 장점: FK 충족, CHECK도 가능
  • 단점: 확장성 측면에서 like 기능을 하는 table이 많아질수록 column이 계속 늘어나는 한계를 지님
CREATE TABLE comments (
	id SERIAL PRIMARY KEY,
	contents VARCHAR(240) NOT NULL
);

CREATE TABLE posts (
	id SERIAL PRIMARY KEY,
	url VARCHAR(200) NOT NULL
);

CREATE TABLE likes (
	id SERIAL PRIMARY KEY,
	user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
	post_id INTEGER REFERENCES posts(id) ON DELETE CASCADE,
	comment_id INTEGER REFERENCES comments(id) ON DELETE CASCADE,
	-- either post_id or comment_id should exist
	CHECK(
		COALESCE((post_id)::BOOLEAN::INTEGER, 0)
		+
		COALESCE((comment_id)::BOOLEAN::INTEGER, 0)
		= 1
	)
);

Solution3

  • 모두 독립적인 테이블로 만들기
  • 단점: 테이블이 많아짐
CREATE TABLE comments (
	id SERIAL PRIMARY KEY,
	contents VARCHAR(240) NOT NULL
);

CREATE TABLE posts (
	id SERIAL PRIMARY KEY,
	url VARCHAR(200) NOT NULL
);

CREATE TABLE comments_likes (
	id SERIAL PRIMARY KEY,
	user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
	comment_id INTEGER REFERENCES comments(id) ON DELETE CASCADE,
);

CREATE TABLE posts_likes (
	id SERIAL PRIMARY KEY,
	user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
	post_id INTEGER REFERENCES posts(id) ON DELETE CASCADE,
);