1. ReferenceField: 외부 문서 참조
관계형 데이터베이스의 외래키와 유사하게, 하나의 문서가 다른 문서를 참조하는 방식입니다. 참조 대상의 ObjectId만 저장되며, 접근 시 실제 문서를 조회합니다.
- 저장 구조: 참조 대상의 고유 식별자(예:
ObjectId)만 저장됨. - 쿼리 동작: 필드 접근 시 즉시 타겟 문서를 조회하여 로드.
- 적합한 상황: 참조 대상이 독립적으로 관리되며, 여러 문서에서 공유되는 경우.
from mongoengine import Document, StringField, ReferenceField
class Publisher(Document):
name = StringField()
class Article(Document):
title = StringField()
publisher = ReferenceField(Publisher) # 출판사 문서 참조
사용 예시:
publisher = Publisher(name="Tech Press").save()
article = Article(title="AI Trends", publisher=publisher).save()
# 접근 시 자동으로 참조 문서 조회
print(article.publisher.name) # 출력: "Tech Press"
2. EmbeddedDocumentField: 내장 문서 구조
하나의 문서 내에 다른 문서를 직접 포함하여 저장하는 방식입니다. 모든 데이터는 부모 문서의 BSON에 함께 저장됩니다.
- 저장 방식: 중첩된 문서 데이터가 부모 문서와 함께 저장됨.
- 쿼리 특성: 부모 문서 조회 시 자동으로 내장 데이터 포함.
- 제약 조건: 내장 문서는 별도로 참조할 수 없으며, 독립적인 컬렉션을 갖지 않음.
from mongoengine import Document, StringField, EmbeddedDocument, EmbeddedDocumentField
class ContactInfo(EmbeddedDocument):
email = StringField()
phone = StringField()
class Profile(Document):
username = StringField()
contact = EmbeddedDocumentField(ContactInfo)
사용 예시:
contact = ContactInfo(email="alice@example.com", phone="123-4567")
profile = Profile(username="alice", contact=contact).save()
# 바로 접근 가능
print(profile.contact.email) # 출력: "alice@example.com"
3. LazyReferenceField: 지연 참조 처리
ReferenceField와 유사하지만, 참조 대상을 실제로 사용할 때까지 로드하지 않는 지연 로딩 기능을 제공합니다. 성능 최적화에 적합합니다.
- 저장 형식: 참조 대상의
ObjectId저장. - 로딩 전략: 접근 시
fetch()호출로만 실제 문서를 불러옴. - 장점: 자주 사용되지 않는 참조 데이터는 무시되어 쿼리 부담 감소.
from mongoengine import Document, StringField, LazyReferenceField
class Contributor(Document):
fullname = StringField()
class Project(Document):
name = StringField()
lead = LazyReferenceField(Contributor)
사용 방법:
contributor = Contributor(fullname="Bob Smith").save()
project = Project(name="API Service", lead=contributor).save()
# 지연 로딩: 필요한 순간에만 데이터 조회
print(project.lead.fetch().fullname) # fetch() 실행 후 출력: "Bob Smith"
비교 요약표
| 구분 | ReferenceField | EmbeddedDocumentField | LazyReferenceField |
|---|---|---|---|
| 저장 방식 | ObjectId 저장 |
내부 데이터 직접 포함 | ObjectId 저장 |
| 데이터 로딩 시점 | 접근 시 즉시 로드 | 부모 문서 조회 시 자동 포함 | 필드 접근 시 fetch()로 지연 로드 |
| 성능 영향 | 항상 추가 쿼리 발생 | 단일 쿼리로 전체 데이터 획득 | 불필요한 쿼리 방지 가능 |
| 문서 간 결합도 | 낮은 결합도 (독립적) | 높은 결합도 (강결합) | 낮은 결합도 (독립적) |
| 문서 크기 | 작은 크기 유지 | 부모 문서 크기 증가 | 작은 크기 유지 |
| 적합한 사용 사례 | 공유되며 독립적으로 관리되는 데이터 | 항상 함께 사용되는 작은 구조적 데이터 | 희소 접근, 성능 최적화 필요 시 |
추천 활용 전략
- ReferenceField: 출판사, 사용자, 카테고리 등 여러 문서에서 공유되는 정보. 독립적인 수정과 관리가 필요한 경우.
- EmbeddedDocumentField: 프로필의 연락처, 주소, 설정 항목처럼 부모와 밀접하게 연결된 작은 데이터 구조.
- LazyReferenceField: 대량의 참조 데이터(예: 고객 정보)가 있지만 대부분의 조회에서는 사용하지 않는 경우. 성능 향상을 위해 지연 로딩이 필요할 때.