Computer >> 컴퓨터 >  >> 프로그래밍 >> MongoDB

MongoDB에서 날짜별로 그룹화하는 방법

MongoDB에서 날짜별로 데이터를 그룹화하려면 애그리게이션(aggregate) 프레임워크를 활용할 수 있습니다. 이 글에서는 실제 예제를 통해 샘플 데이터 생성부터 날짜 기준 그룹화 쿼리 작성까지 전 과정을 단계별로 살펴보겠습니다.

1. 샘플 컬렉션 생성하기

먼저 문서(document)가 포함된 컬렉션을 생성합니다. 아래 쿼리는 사용자 로그인 시간을 UserLoginDateTime 필드에 저장하는 문서들을 차례로 삽입합니다:

> db.groupByDateDemo.insertOne({"UserLoginDateTime":new ISODate()});
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5c6ee4df6fd07954a4890695")
}
> db.groupByDateDemo.insertOne({"UserLoginDateTime":new ISODate("2019-01-31 15:20:09.234Z")});
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5c6ee51c6fd07954a4890696")
}
> db.groupByDateDemo.insertOne({"UserLoginDateTime":new ISODate("2017-04-21 16:12:13.240Z")});
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5c6ee5336fd07954a4890697")
}
> db.groupByDateDemo.insertOne({"UserLoginDateTime":new ISODate("2016-05-25 19:11:21.130Z")});
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5c6ee54b6fd07954a4890698")
}
> db.groupByDateDemo.insertOne({"UserLoginDateTime":new ISODate("2016-05-25 19:11:21.130Z")});
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5c6ee8de6fd07954a4890699")
}
> db.groupByDateDemo.insertOne({"UserLoginDateTime":new ISODate()});
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5c6ee8e76fd07954a489069a")
}

2. 전체 문서 조회하기

find() 메서드를 사용하면 컬렉션에 저장된 모든 문서를 확인할 수 있습니다:

> db.groupByDateDemo.find().pretty();

실행 결과는 다음과 같습니다:

{
   "_id" : ObjectId("5c6ee4df6fd07954a4890695"),
   "UserLoginDateTime" : ISODate("2019-02-21T17:50:23.076Z")
}
{
   "_id" : ObjectId("5c6ee51c6fd07954a4890696"),
   "UserLoginDateTime" : ISODate("2019-01-31T15:20:09.234Z")
}
{
   "_id" : ObjectId("5c6ee5336fd07954a4890697"),
   "UserLoginDateTime" : ISODate("2017-04-21T16:12:13.240Z")
}
{
   "_id" : ObjectId("5c6ee54b6fd07954a4890698"),
   "UserLoginDateTime" : ISODate("2016-05-25T19:11:21.130Z")
}
{
   "_id" : ObjectId("5c6ee8de6fd07954a4890699"),
   "UserLoginDateTime" : ISODate("2016-05-25T19:11:21.130Z")
}
{
   "_id" : ObjectId("5c6ee8e76fd07954a489069a"),
   "UserLoginDateTime" : ISODate("2019-02-21T18:07:35.208Z")
}

3. 날짜별 그룹화 쿼리 작성하기

이제 $group 연산자와 날짜 연산자를 조합하여 날짜별로 그룹화해 보겠습니다. 핵심은 $dayOfYear(연중 몇 번째 날인지) 값에 $year(연도) 값에 400을 곱한 수를 더해 고유한 그룹 키를 만드는 것입니다. 이렇게 하면 서로 다른 연도의 같은 날짜도 하나의 그룹으로 잘못 묶이지 않습니다.

> db.groupByDateDemo.aggregate([
... { $group: {
... _id: {
... $add: [
... { $dayOfYear: "$UserLoginDateTime"},
... { $multiply:
... [400, {$year: "$UserLoginDateTime"}]
... }
... ]},
... NumberOfTimes: { $sum: 1 },
... f: {$min: "$UserLoginDateTime"}
... }
... },
... { $sort: {_id: 1} },
... { $limit: 10 },
... { $project: { date: "$f", NumberOfTimes: 1, _id: 0} }
... ]);

위 쿼리의 실행 결과입니다:

{ "NumberOfTimes" : 2, "date" : ISODate("2016-05-25T19:11:21.130Z") }
{ "NumberOfTimes" : 1, "date" : ISODate("2017-04-21T16:12:13.240Z") }
{ "NumberOfTimes" : 1, "date" : ISODate("2019-01-31T15:20:09.234Z") }
{ "NumberOfTimes" : 2, "date" : ISODate("2019-02-21T17:50:23.076Z") }

쿼리 동작 원리 살펴보기

  • $dayOfYear: 해당 날짜가 연중 몇 번째 날인지 숫자로 반환합니다.
  • $multiply: 연도 값에 400을 곱해 연도 간 그룹 키 충돌을 방지합니다.
  • $sum: 1: 각 그룹에 속한 문서의 개수를 집계합니다.
  • $min: 그룹 내 가장 빠른 로그인 시간을 대표 날짜로 선택합니다.
  • $sort / $limit: 결과를 오름차순으로 정렬하고 상위 10개만 가져옵니다.
  • $project: 출력 필드를 dateNumberOfTimes로 제한해 깔끔한 결과를 만듭니다.

결과를 해석해 보면, 2016년 5월 25일과 2019년 2월 21일에는 각각 2번의 로그인이 기록되어 있고, 나머지 날짜에는 1번씩 로그인한 것을 확인할 수 있습니다. 이처럼 애그리게이션 파이프라인을 활용하면 MongoDB에서 일별 접속 횟수 같은 날짜 단위 통계를 손쉽게 추출할 수 있으며, 월별·연도별 집계로도 응용할 수 있습니다.