MongoEngine에서 QuerySet을 다룰 때 .only() 메서드는 특정 필드만 선택적으로 가져오는 필드 프로젝션(Field Projection)을 수행하여 쿼리 성능을 최적화하는 데 사용됩니다. 이 메서드의 내부 동작 방식과 반환되는 데이터의 특성에 대해 살펴보겠습니다.
.only() 메서드의 핵심 동작
.only('field_name')은 MongoDB 수준에서 반환될 필드를 제한합니다. 이를 통해 불필요한 데이터 로딩을 방지하고 메모리 사용량과 네트워크 전송량을 크게 줄일 수 있습니다.
모델 정의 및 데이터 조회 예제
다음과 같은 사용자 활동 로그를 저장하는 문서 모델이 있다고 가정해 보겠습니다.
from mongoengine import Document, StringField, DateTimeField, DictField
import datetime
class ActivityLog(Document):
user_id = StringField(required=True)
action = StringField(required=True)
timestamp = DateTimeField(default=datetime.datetime.utcnow)
payload = DictField()
이제 user_id와 action 필드만 명시적으로 요청하는 쿼리를 실행합니다.
# 특정 필드만 프로젝션하여 조회
logs = ActivityLog.objects.only('user_id', 'action')
반환 결과 및 필드 접근 특성
위 쿼리의 결과로 반환되는 객체는 일반적인 QuerySet이지만, 내부 문서 객체는 제한된 필드만 포함하고 있습니다.
- 기본 키(_id) 자동 포함: 명시적으로 지정하지 않더라도 MongoDB의 기본 동작에 따라
_id필드는 항상 결과에 포함됩니다. - 지정된 필드 접근:
user_id와action은 정상적으로 읽을 수 있습니다. - 미포함 필드 접근 시 예외: 프로젝션되지 않은
timestamp나payload필드에 접근하려고 하면mongoengine.errors.ValidationError가 발생하며 프로그램이 중단됩니다.
for log in logs:
print(log.id) # 정상 출력: 기본 키(_id) 값
print(log.user_id) # 정상 출력: 프로젝션된 user_id 값
print(log.action) # 정상 출력: 프로젝션된 action 값
# 미로드 필드 접근 시 예외 발생
# print(log.timestamp) # mongoengine.errors.ValidationError 발생
주요 고려사항 및 활용 시나리오
1. 다중 필드 프로젝션
하나의 필드뿐만 아니라 쉼표로 구분하여 여러 필드를 동시에 지정할 수 있습니다.
partial_logs = ActivityLog.objects.only('user_id', 'action', 'timestamp')
2. 네트워크 및 메모리 최적화
문서의 크기가 크거나(예: payload에 대용량 JSON이 포함된 경우) 결과 집합이 방대할 때 .only()를 사용하면 네트워크 대역폭과 애플리케이션의 메모리 점유율을 획기적으로 낮출 수 있습니다.
3. 특정 목적의 데이터 집계
전체 문서가 아닌 특정 속성만을 활용한 통계나 집계 작업에 매우 유용합니다. 예를 들어, 특정 기간 동안의 고유 사용자 ID 목록을 추출할 때 다음과 같이 간결하게 작성할 수 있습니다.
unique_users = {log.user_id for log in ActivityLog.objects.only('user_id')}