Mongoose-Many To Many Relationship
Mongoose에서 Many-to-Many 관계 구현하는 방법
Mongoose에서 Many-to-Many(다대다) 관계를 구현하는 방식은 보통 두 개의 컬렉션을 ObjectId를 활용한 ref 방식으로 연결하거나, 중간 테이블(조인 테이블 역할)을 사용하여 구성합니다.
1. 직접 ObjectId 배열을 활용한 Many-to-Many 관계
가장 기본적인 Many-to-Many 관계는 각 모델에서 상대 모델의 ObjectId를 배열로 저장하는 방식입니다.
예제: User와 Group 간 Many-to-Many 관계
하나의 유저(User)는 여러 그룹(Group)에 속할 수 있음.
하나의 그룹(Group)도 여러 유저(User)를 포함할 수 있음.
✅ 장점: 간단한 구조로 쉽게 구현 가능
❌ 단점: User와 Group의 데이터를 동기화하려면 추가적인 코드가 필요 (데이터 정합성 문제 발생 가능)
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: String,
email: String,
groups: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Group' }] // 여러 개의 그룹을 가질 수 있음
});
const GroupSchema = new mongoose.Schema({
name: String,
users: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }] // 여러 명의 유저를 포함할 수 있음
});
const User = mongoose.model('User', UserSchema);
const Group = mongoose.model('Group', GroupSchema);
데이터 저장 예제
async function createData() {
const user1 = await User.create({ name: 'Alice', email: 'alice@example.com' });
const user2 = await User.create({ name: 'Bob', email: 'bob@example.com' });
const group1 = await Group.create({ name: 'Developers' });
const group2 = await Group.create({ name: 'Designers' });
// 관계 설정
user1.groups.push(group1._id, group2._id);
user2.groups.push(group1._id);
group1.users.push(user1._id, user2._id);
group2.users.push(user1._id);
await user1.save();
await user2.save();
await group1.save();
await group2.save();
console.log('데이터 저장 완료');
}
Many-to-Many 관계 데이터 조회 (populate 활용)
async function getUserWithGroups(userId) {
const user = await User.findById(userId).populate('groups');
console.log(user);
}
async function getGroupWithUsers(groupId) {
const group = await Group.findById(groupId).populate('users');
console.log(group);
}
2. 중간 컬렉션(Join Table) 활용 (더 정교한 방식)
Mongoose에서 Many-to-Many 관계 구현하는 방법
Mongoose에서 Many-to-Many(다대다) 관계를 구현하는 방식은 보통 두 개의 컬렉션을 ObjectId를 활용한 ref 방식으로 연결하거나, **중간 테이블(조인 테이블 역할)**을 사용하여 구성합니다.
직접 ObjectId 배열을 활용한 Many-to-Many 관계
가장 기본적인 Many-to-Many 관계는 각 모델에서 상대 모델의 ObjectId를 배열로 저장하는 방식입니다.
예제: User와 Group 간 Many-to-Many 관계
하나의 유저(User)는 여러 그룹(Group)에 속할 수 있음.
하나의 그룹(Group)도 여러 유저(User)를 포함할 수 있음.
javascript
복사
편집
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: String,
email: String,
groups: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Group' }] // 여러 개의 그룹을 가질 수 있음
});
const GroupSchema = new mongoose.Schema({
name: String,
users: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }] // 여러 명의 유저를 포함할 수 있음
});
const User = mongoose.model('User', UserSchema);
const Group = mongoose.model('Group', GroupSchema);
데이터 저장 예제
javascript
복사
편집
async function createData() {
const user1 = await User.create({ name: 'Alice', email: 'alice@example.com' });
const user2 = await User.create({ name: 'Bob', email: 'bob@example.com' });
const group1 = await Group.create({ name: 'Developers' });
const group2 = await Group.create({ name: 'Designers' });
// 관계 설정
user1.groups.push(group1._id, group2._id);
user2.groups.push(group1._id);
group1.users.push(user1._id, user2._id);
group2.users.push(user1._id);
await user1.save();
await user2.save();
await group1.save();
await group2.save();
console.log('데이터 저장 완료');
}
Many-to-Many 관계 데이터 조회 (populate 활용)
javascript
복사
편집
async function getUserWithGroups(userId) {
const user = await User.findById(userId).populate('groups');
console.log(user);
}
async function getGroupWithUsers(groupId) {
const group = await Group.findById(groupId).populate('users');
console.log(group);
}
✅ 장점: 간단한 구조로 쉽게 구현 가능
❌ 단점: User와 Group의 데이터를 동기화하려면 추가적인 코드가 필요 (데이터 정합성 문제 발생 가능)
2. 중간 컬렉션(Join Table) 활용 (더 정교한 방식)
위 방식은 간단하지만, 추가 정보를 저장할 수 없고 데이터 정합성을 유지하기 어렵다는 단점이 있습니다.
이를 해결하기 위해 중간 컬렉션(Join Table 역할)을 사용하여 다대다 관계를 명확하게 정의할 수 있습니다.
✅ 장점: 추가 정보를 저장 가능, 데이터 정합성 유지
❌ 단점: populate() 쿼리가 많아질 경우 성능 저하 가능
예제: User와 Group을 연결하는 Membership 컬렉션 추가
Membership 모델을 추가하여 중간 테이블 역할을 수행
Membership은 User와 Group을 참조하면서 가입 날짜 등의 추가 정보를 저장 가능
const MembershipSchema = new mongoose.Schema({
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
group: { type: mongoose.Schema.Types.ObjectId, ref: 'Group' },
joinedAt: { type: Date, default: Date.now } // 가입 날짜 추가
});
const Membership = mongoose.model('Membership', MembershipSchema);
데이터 저장 예제
async function createMembership() {
const user = await User.create({ name: 'Charlie', email: 'charlie@example.com' });
const group = await Group.create({ name: 'Frontend Engineers' });
// Membership 생성
await Membership.create({ user: user._id, group: group._id });
console.log('Membership 관계 저장 완료');
}
Many-to-Many 관계 조회
async function getUserGroups(userId) {
const memberships = await Membership.find({ user: userId }).populate('group');
console.log(memberships);
}
async function getGroupUsers(groupId) {
const memberships = await Membership.find({ group: groupId }).populate('user');
console.log(memberships);
}