TDL

Mongoose-One To Many Relationship


BACKEND
NESTJS

Mongoose에서 One-to-Many 관계(1:N 관계) 구현 방법

MongoDB에서 One-to-Many (1:N) 관계를 구현하는 방법은 크게 두 가지로 나눈다.

  • Reference 방식 (ObjectId 참조) → 정규화된 데이터 구조

  • Embed 방식 (내장 배열) → 비정규화된 데이터 구조

1. Reference 방식 (ObjectId 참조)

  • 다른 컬렉션을 참조(ref)하여 One-to-Many 관계를 설정하는 방식

  • 각 Post는 User를 참조하고, User는 여러 개의 Post를 가질 수 있음.

  • populate()를 사용하여 관계된 데이터를 조회할 수 있음.

  • 데이터가 많아지더라도 성능이 비교적 좋고 확장성이 뛰어남.

장점: Post가 독립적인 컬렉션으로 관리되어 확장성 좋음

단점: 추가적인 populate() 연산이 필요하여 성능이 다소 느릴 수 있음

예제: User(사용자)와 Post(게시글) 관계 (1:N)

const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({
  name: String,
  email: String,
  posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }] // Post 컬렉션과 1:N 관계
});

const PostSchema = new mongoose.Schema({
  title: String,
  content: String,
  user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } // User 참조
});

const User = mongoose.model('User', UserSchema);
const Post = mongoose.model('Post', PostSchema);
데이터 저장
async function createData() {
  const user = await User.create({ name: 'Alice', email: 'alice@example.com' });

  const post1 = await Post.create({ title: '첫 번째 게시글', content: '내용 1', user: user._id });
  const post2 = await Post.create({ title: '두 번째 게시글', content: '내용 2', user: user._id });

  // User의 posts 배열에 추가
  user.posts.push(post1._id, post2._id);
  await user.save();

  console.log('데이터 저장 완료');
}
데이터 조회 (populate 활용)

async function getUserWithPosts(userId) {
  const user = await User.findById(userId).populate('posts');
  console.log(user);
}

2. Embed 방식 (내장 배열)

posts 데이터를 User 문서에 직접 저장하는 방식

  • 한 번의 쿼리로 데이터를 가져올 수 있어 속도가 빠름

  • 데이터 크기가 너무 커지면 성능 저하가 발생할 수 있음

장점: populate() 없이도 한 번의 조회로 모든 데이터를 가져올 수 있음

단점: 게시글이 많아지면 User 문서가 너무 커지고, 개별 게시글을 독립적으로 관리하기 어려움

예제: Embed 방식의 User 모델

const UserSchema = new mongoose.Schema({
  name: String,
  email: String,
  posts: [
    {
      title: String,
      content: String
    }
  ]
});

const User = mongoose.model('User', UserSchema);

데이터 저장
async function createUserWithPosts() {
  const user = await User.create({
    name: 'Bob',
    email: 'bob@example.com',
    posts: [
      { title: '첫 번째 게시글', content: '내용 1' },
      { title: '두 번째 게시글', content: '내용 2' }
    ]
  });

  console.log('저장 완료', user);
}