이 장에서는 MongoDB 통계 분석에 대한 상세한 설명을 소개하는데, 이는 주로 집계 파이프라인을 통해 이루어집니다. 이는 SQL의 "group by" 문과 유사합니다. MongoDB 셸에서는 통계 분석을 db.collection.aggregate() 함수를 사용하여 구현합니다.

선행 튜토리얼

MongoDB 집계 파이프라인

일반적인 단계

  • $match를 사용하여 대상 데이터를 필터링합니다.
  • $group을 사용하여 데이터를 그룹화하고 계산합니다.
  • 결과를 정렬하기 위해 $sort를 사용합니다 (선택 사항).

테스트 데이터

orders 컬렉션의 데이터는 다음과 같습니다.

{ _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 }
{ _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 }
{ _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 }
{ _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 }
{ _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 }

aggregate 함수

db.collection.aggregate(pipeline) 설명:

  • 파이프라인은 배열 매개변수를 취하며, 각 요소는 처리 단계를 나타냅니다.

예제

db.orders.aggregate([
                     { $match: { status: "A" } },  // 첫 번째 단계
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },   // 두 번째 단계
                     { $sort: { total: -1 } }  // 세 번째 단계
                   ])

동등한 SQL

select sum(amount) as total from orders 
        where status="A" 
        group by cust_id 
        order by total desc

$match 단계

형식:

{ $match: { <query> } }

설명:

  • <query> MongoDB 쿼리 조건

쿼리 조건을 설정하는 데 사용됩니다. $match가 무시되면 모든 데이터를 쿼리하는 것을 의미합니다.

팁: MongoDB 쿼리 구문에 익숙하지 않다면, 이전 장을 참조해주세요.

$group 단계

SQL의 group by 절과 유사하며, 데이터를 그룹화한 다음 그룹화된 데이터에 대해 일련의 통계 계산을 수행하기 위해 사용됩니다.

$group의 기본 사용법

구문:

{
  $group:
    {
      _id: <expression>, // 예: 어느 필드를 기준으로 그룹화할 것인지
      <field1>: { <accumulator1> : <expression1> },  // 집계 조작, N개의 집계 조작을 추가할 수 있음
      ...
    }
 }

설명:

  • - 사용자 정의 통계 지표의 이름, 총 N개가 될 수 있음
  • - 집계 함수, sum, avg와 같은 SQL의 집계 함수와 유사하지만, MongoDB의 집계 함수는 $를 접두어로 하는 것이 차이점입니다. 예: $sum, $avg
  • - 집계 함수의 매개변수로, 일반적으로 카운트할 필드 값, "$필드 이름" 형식으로 문서 필드를 참조

예제:

db.orders.aggregate([
                     {
					 	$group: { 
							_id: "$cust_id",
							total: { $sum: "$amount" }, // 첫 번째로 계산된 지표 total을 추가하고, $sum 덧셈 연산자를 사용합니다.
							amount_avg: {$avg: "$amount"}  // 두 번째로 계산된 지표 avg를 추가하고, $avg 평균 계산 연산자를 사용합니다.
						} 
					}
               ])

결과:

{ "_id" : "abc1", "total" : 75, "amount_avg" : 37.5 }
{ "_id" : "xyz1", "total" : 250, "amount_avg" : 83.33333333333333 }

동등한 SQL:

select 
	sum(amount) as  total,
	avg(amount) as amount_avg
from orders 
group by cust_id

$group 집계 함수

$group에서 자주 사용되는 집계 함수는 다음과 같습니다:

연산자 설명 예시
$avg 평균 계산 {$avg: "$amount"}
$sum 합계 {$sum: "$amount"}
$max 최댓값 {$max: "$amount"}
$min 최솟값 {$min: "$amount"}
$first 그룹화 후 데이터 반환, 첫 번째 문서의 내용 {$first: "$amount"}
$last 그룹화 후 데이터 반환, 마지막 문서의 내용 {$last: "$amount"}
$push 그룹화 후 데이터 반환 { $push: { ord_date: "$ord_date", amount: "$amount" }
$addToSet 그룹화 후 데이터 반환, $push와 다르게 중복을 제거함 { $addToSet: "$amount" }

$push 예시

db.orders.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all: { $push: { ord_date: "$ord_date", amount: "$amount" } } // ord_date와 amount 필드의 값
         }
     }
   ]
)

결과

{ "_id" : "abc1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 50 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 25 } ] }
{ "_id" : "xyz1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 100 }, { "ord_date" : "2021-04-20 00:00:00", "amount" : 25 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 125 } ] }

$addToSet 예시

db.orders.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all_amount: { $addToSet: "$amount" } // 모든 중복되지 않는 amount 값 반환
         }
     }
   ]
)

결과

{ "_id" : "abc1", "all_amount" : [ 25, 50 ] }
{ "_id" : "xyz1", "all_amount" : [ 100, 25, 125 ] }

$sort:

$sort 단계는 일반적으로 집계된 데이터를 정렬하기 위해 마지막에 배치됩니다.

형식:

{ $sort: { <field1>: <정렬 순서>, <field2>: <정렬 순서> ... } }

설명:

  • , - 정렬할 필드 이름, 여러 필드를 지원합니다.
  • <정렬 순서> - 정렬 방향, 내림차순은 -1, 오름차순은 1입니다.

예시:

db.orders.aggregate([
                     { $match: { status: "A" } },
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
                     { $sort: { total: -1 } }
                   ])

집계 페이지네이션

$limit과 $skip 연산자를 사용하여 페이지네이션을 구현할 수 있습니다.

예시:

db.orders.aggregate([
                     { $match: { status: "A" } },
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
                     { $sort: { total: -1 } },
					 { $limit: 5 }, // 반환된 레코드 수 제한, 페이지네이션의 페이지 크기와 유사함.
					 { $skip: 1 } // 특정 레코드 수 건너뛰기, SQL의 오프셋과 유사함.
                   ])