문제 상황
MongoDB에 저장된 데이터를 기간별로 가공해서 출력해주는 코드를 만들다가 이상한 점을 하나 발견했다.
createdAt 같은 날짜/시간 필드가 문자열(string)로 저장돼 있던 것.
처음엔 model에서 datetime으로 지정했으니까 당연히 datetime으로 들어갔을 거라 생각했는데, 막상 DB를 까보니까 "2024-01-01T12:00:00"처럼 string으로 저장되어 있던 것을 깨달았다.
그래서 코드 전체를 훑기 시작했다.
DTO, Model엔 분명히 datetime 타입으로 잘 들어가 있었고, 이상 없어 보였다.
그런데 문제는 라우터 코드였다.
라우터에서 데이터를 서비스 쪽으로 넘기기 전에 jsonable_encoder(data)로 한번 감싸고 있었는데, 이게 문제의 시작이었다.
jsonable_encoder는 datetime 객체를 자동으로 문자열로 변환해서 JSON 직렬화가 가능한 형태로 만들어준다. API 응답을 줄 땐 아주 편한 기능인데, 문제는 그걸 DB에 저장할 때도 써버리면 datetime이 문자열로 저장된다는 것을 알았다.
이걸 모르고 있다가, 나중에 날짜 필터 쿼리를 날릴 때 원하는 데이터가 하나도 안 나와서 한참 헤맸다. string으로 저장돼 있으니 당연히 {"$gte": datetime(...)} 같은 쿼리는 안 먹히는 거다.
정리한 결론
- DB에 저장하거나 업데이트할 때는 data.dict()를 써야 한다. 그래야 datetime도 제대로 들어간다.
- API 응답으로 데이터를 보낼 때는 jsonable_encoder()를 쓰는 게 맞다. 이때는 프론트엔드가 받아들이기 쉬운 형식이 필요하니까.
예시로 코드 정리하면 이렇다
# 저장할 때 (Create, Update)
data_to_save = data.dict() # 전달받은 인자 형태를 잘 유지해서 dict로 담기
collection.insert_one(data_to_save) # 또는 서비스 코드로 전달
# 응답할 때 (Read)
result = collection.find_one({...})
return jsonable_encoder(result) # jsonable_encoder로 감싸서 전달(프론트에서 처리하기 수월하게 ~)
마무리
이번 경험으로 확실히 느낀 건, 무심코 쓴 인코더(jsonable_encoder) 하나가 데이터 전체 흐름을 엉망으로 만들 수 있다는 거다. FastAPI 쓸 때는 내부에서 쓸 데이터와 응답용 데이터를 명확히 구분해서 처리하는 습관을 들여야겠다.
그리고 무엇보다, 평소에 DB를 자주 까보는 습관이 얼마나 중요한지도 다시 깨달았다.
'개발 일상' 카테고리의 다른 글
| YOLO 객체 감지 후 위험 영역 판단 로직 개선기 (1) | 2025.06.10 |
|---|---|
| 대량의 파일, 효율적으로 압축 & 전송하기 – 우분투 기반 백업 최적화 (2) | 2025.06.02 |
| MongoDB Aggregation을 활용한 통계 API 구현(python) (1) | 2025.05.22 |
| 주기적인 MongoDB 서비스 Down 증상 해결 (0) | 2025.05.19 |
| [React.js] setTimeout 사용 시 최신 상태(state)가 반영되지 않는 이슈 처리 (0) | 2025.04.07 |
