MongoDB는 탈 RDBMS를 의미하는 표준화된 구조적 질의 언어가 없는 데이터베이스 또는 관계를 갖지 않는 데이터베이스의 NoSQL의 Document Database의 한 종류이다.
이처럼 MongoDB는 관계형 데이터베이스가 아니지만 스키마를 통해 관계를 설정함으로써 유지보수가 용이하고 데이터를 관리하기 쉽게 할 수 있다.
모든 1:1 data를 key-value-pair로 저장한다.
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
}
});
const userInfoSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
phone: {
type: String,
required: true
}
});
const User = mongoose.model('User', userSchema);
const UserInfo = mongoose.model('UserInfo', userInfoSchema);
우선 userSchema
와 userInfoSchema
로 각각의 스키마를 정의했다. userInfoSchema
에서는 user
필드를 통해 User
모델과 연결하여 일대일 관계를 정의했다. 이때 ObjectId
고유식별자를 활용하여 고유값을 연결한다.
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment'
}]
});
const commentSchema = new mongoose.Schema({
content: {
type: String,
required: true
},
post: {
type: mongoose.Schema.Types.ObjcetId,
ref: 'Post'
}
});
const Post = mongoose.model('Post', postSchema);
const Comment = mongoose.model('Comment', commentSchema);
게시글과 댓글을 예시로 들면, 서로의 스키마를 필드로 정의하고 있다. 여기서 postSchema
는 comments
필드를 []로 정의했는데 이 의미는 comments
필드가 배열로 받겠다는 의미이다.
일대다 관계는 임베디드 형식으로 서로를 참조하는 것보다는 참조형 형식으로 참조하는 것이 일반적이다.
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
tags: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Tag'
}]
});
const tagSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}]
});
const Post = mongoose.model('Post', postSchema);
const Tag = mongoose.model('Tag', tagSchema);
참조 필드 방식은 스키마 각각에 배열을 사용하여 서로를 참조하는 방법이다.
이 방식은 간단하고 직접적이며, 작은 규모의 프로젝트나 단순한 관계에서는 무리없이 작동한다.
const studentSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
required: true
}
});
const subjectSchema = new mongoose.Schema({
name: {
type: String,
required: true
}
});
// 중간 컬렉션
const enrollmentSchema = new Schema({
student: {
type: mongoose.Schema.Types.ObjectId
ref: 'Student'
},
subject: {
type: mongoose.Schema.Types.ObjectId
ref: 'Subject'
}
});
const student = new mongoose.model('Student', studentSchema);
const subject = new mongoose.model('Subject', subjectSchema);
const enrollment = new mongoose.model('Enrollment', enrollmentSchema);
중간 컬렉션을 활용할 때는 studentSchema
와 subjectSchema
가 서로 참조하지 않고 중간 컬렉션 모델의 인스턴스에 각각의 모델과 관련된 필드를 지정한다.
유연성: 중간 컬렉션을 통해 추가 정보나 관계 속성을 저장할 수 있으므로 더 복잡한 관계를 다루기에 유용하다.
명확한 관계: 중간 컬렉션을 사용하면 두 스키마 간의 관계를 보다 명시적으로 이해할 수 있다.
성능 최적화: 중간 컬렉션을 사용하면 관련 데이터를 더 효과적으로 쿼리하고 필터링할 수 있으며, 복잡한 쿼리를 수행하기에 좀 더 효율적일 수 있다.
일반적인 관행: 중간 컬렉션을 사용하는 방식은 관계형 데이터베이스에서의 다대다 관계를 모델링하는 일반적인 방식과 유사하다. 따라서 이 방식을 사용하는 것은 개발자나 데이터베이스 관리자가 이해하고 유지보수하기 쉬울 수 있다.
❗어떤 방식을 선택할지는 프로젝트의 요구 사항과 복잡성에 따라 다를 수 있다. 복잡한 관계나 추가 정보가 필요한 경우 중간 컬렉션을 사용하는 것이 더 유용할 수 있다.