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);
}