MongoDB에서 저장된 날짜 데이터 중 특정 시간대(예: 오전 6시~9시 사이)에 해당하는 레코드만 추출하고 싶은 경우가 있습니다. 이번 글에서는 ISODate 형식으로 저장된 날짜 필드를 대상으로, 집계 파이프라인의 $redact 연산자를 활용해 원하는 시간 범위의 문서만 조회하는 방법을 알아보겠습니다.
1. 샘플 컬렉션 생성
먼저 DueDate 필드에 ISODate 값을 담은 문서들을 삽입하여 테스트용 컬렉션을 만들어 보겠습니다.
> db.demo178.insertOne({"DueDate":new ISODate("2019-01-10T06:18:20.474Z")});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e397bd89e4f06af551997f5")
}
> db.demo178.insertOne({"DueDate":new ISODate("2020-11-10T18:05:11.474Z")});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e397bf39e4f06af551997f6")
}
> db.demo178.insertOne({"DueDate":new ISODate("2020-03-15T07:05:10.474Z")});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e397c039e4f06af551997f7")
}
> db.demo178.insertOne({"DueDate":new ISODate("2020-06-11T16:05:10.474Z")});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e397c0f9e4f06af551997f8")
}2. 전체 문서 확인하기
find() 메서드를 사용하면 컬렉션에 저장된 모든 문서를 확인할 수 있습니다.
> db.demo178.find();
실행 결과는 다음과 같습니다.
{ "_id" : ObjectId("5e397bd89e4f06af551997f5"), "DueDate" : ISODate("2019-01-10T06:18:20.474Z") }
{ "_id" : ObjectId("5e397bf39e4f06af551997f6"), "DueDate" : ISODate("2020-11-10T18:05:11.474Z") }
{ "_id" : ObjectId("5e397c039e4f06af551997f7"), "DueDate" : ISODate("2020-03-15T07:05:10.474Z") }
{ "_id" : ObjectId("5e397c0f9e4f06af551997f8"), "DueDate" : ISODate("2020-06-11T16:05:10.474Z") }3. 시간 범위로 날짜 레코드 조회하기
이제 핵심인 조회 쿼리입니다. 아래 쿼리는 $redact 연산자와 $cond, $and, 그리고 날짜 연산자인 $hour를 조합하여, 시(hour) 값이 5보다 크고 9보다 작은 문서만 걸러냅니다.
> db.demo178.aggregate([
... {
... "$redact": {
... "$cond": {
... "if": {
... "$and": [
... { "$gt": [ {"$hour": "$DueDate"}, 5] },
... { "$lt": [ {"$hour": "$DueDate"}, 9] }
... ]
... },
... "then": "$$KEEP",
... "else": "$$PRUNE"
... }
... }
... }
...])4. 실행 결과
조건에 맞는 문서만 반환되는 것을 확인할 수 있습니다.
{ "_id" : ObjectId("5e397bd89e4f06af551997f5"), "DueDate" : ISODate("2019-01-10T06:18:20.474Z") }
{ "_id" : ObjectId("5e397c039e4f06af551997f7"), "DueDate" : ISODate("2020-03-15T07:05:10.474Z") }쿼리 동작 원리 정리
- $hour: ISODate 값에서 시(hour) 부분만 숫자로 추출합니다. 예를 들어
06:18:20이면6을 반환합니다. - $gt / $lt: 각각 초과, 미만 비교를 수행하여 시간이 5보다 크고 9보다 작은지 판단합니다.
- $redact + $cond: 조건이 참이면
$$KEEP으로 해당 문서를 유지하고, 거짓이면$$PRUNE으로 제거합니다.
결과적으로 오전 6시와 7시에 생성된 두 개의 문서만 남게 됩니다. 이처럼 $redact를 활용하면 별도의 $match 단계 없이도 날짜·시간 기반의 세밀한 필터링을 하나의 파이프라인 단계에서 처리할 수 있습니다. 만약 분(minute)이나 초(second) 단위까지 조건을 걸고 싶다면 $minute, $second 연산자를 동일한 방식으로 활용하면 됩니다.