MongoDB에서 특정 기간(두 날짜 사이)에 속한 문서의 개수를 세거나 특정 필드의 합계를 구하려면 애그리게이션(aggregation) 파이프라인을 활용하면 됩니다. $match 단계에서 비교 연산자인 $gte(이상)와 $lte(이하)로 날짜 범위를 지정하고, $group 단계에서 $sum을 사용해 합계와 개수를 한 번에 계산할 수 있습니다.
1. 샘플 컬렉션 생성하기
먼저 예제로 사용할 컬렉션에 문서를 삽입해 보겠습니다.
> db.countandsumdemo.insertOne({"Value":10,"created_at":ISODate('2019-10-11')});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e038e6df5e889d7a51994fa")
}
> db.countandsumdemo.insertOne({"Value":50,"created_at":ISODate('2019-01-31')});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e038e77f5e889d7a51994fb")
}
> db.countandsumdemo.insertOne({"Value":100,"created_at":ISODate('2019-06-31')});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e038e8af5e889d7a51994fc")
}참고로 위 예제에서 '2019-06-31'은 실제로 존재하지 않는 날짜이기 때문에(6월은 30일까지), MongoDB가 자동으로 다음 날인 7월 1일로 변환하여 저장합니다.
2. 전체 문서 조회하기
find() 메서드를 사용하면 컬렉션의 모든 문서를 확인할 수 있습니다.
> db.countandsumdemo.find().pretty();
위 쿼리는 다음과 같은 결과를 출력합니다.
{
"_id" : ObjectId("5e038e6df5e889d7a51994fa"),
"Value" : 10,
"created_at" : ISODate("2019-10-11T00:00:00Z")
}
{
"_id" : ObjectId("5e038e77f5e889d7a51994fb"),
"Value" : 50,
"created_at" : ISODate("2019-01-31T00:00:00Z")
}
{
"_id" : ObjectId("5e038e8af5e889d7a51994fc"),
"Value" : 100,
"created_at" : ISODate("2019-07-01T00:00:00Z")
}3. 두 날짜 사이의 개수와 합계 구하기
다음은 2019년 5월 1일부터 2019년 12월 31일 사이에 생성된 문서의 개수(COUNT)와 Value 필드의 합계(SUM)를 구하는 애그리게이션 쿼리입니다.
> db.countandsumdemo.aggregate(
... [{
... $match: {
... created_at: {
... $gte: new Date('2019-05-01'),
... $lte: new Date('2019-12-31')
... }
... }
... }, {
... $group: {
... _id: null,
... SUM: {
... $sum: "$Value"
... },
... COUNT: {
... $sum: 1
... }
... }
... }]
... );쿼리 동작 원리
- $match:
created_at필드 값이 시작 날짜($gte) 이상이면서 종료 날짜($lte) 이하인 문서만 필터링합니다. - $group:
_id: null로 지정해 모든 문서를 하나의 그룹으로 묶습니다. - $sum: "$Value": 그룹 내 문서들의
Value필드 값을 모두 더합니다. - $sum: 1: 문서 하나당 1씩 더해 총 개수를 계산합니다.
실행 결과
{ "_id" : null, "SUM" : 110, "COUNT" : 2 }결과를 해석해 보면, 지정한 기간에 해당하는 문서는 2개이며(10월 11일의 10, 7월 1일의 100), 이들 Value의 합계는 110입니다. 1월 31일 데이터는 조회 범위보다 이전이므로 집계에서 제외된 것을 확인할 수 있습니다.