집계 파이프라인 (Aggregation Pipeline)

집계 파이프라인 (Aggregation Pipeline)

집계 작업이란

집계(Aggregation) 작업은 여러 문서를 처리하고 계산된 결과를 돌려줍니다. MongoDB를 쓰다 보면 "이 컬렉션에 있는 값들을 묶어서 통계를 내야겠다" 하는 순간이 꼭 오는데요, 그때 이 집계 작업이 동작합니다. 구체적으로는 이런 일들을 할 수 있어요.

  • 여러 문서에서 값을 그룹화합니다.
  • 그룹화된 데이터에서 단일 결과를 계산합니다.
  • 시간에 따른 데이터 변화를 분석합니다.
  • 데이터의 최신 버전을 조회합니다.

MongoDB의 집계 연산자(aggregation operator)를 쓰면 데이터를 다른 플랫폼으로 옮기지 않고도 클러스터 안에서 바로 분석을 실행할 수 있습니다.

시작하기

집계 작업을 수행하는 방법은 두 가지입니다.

  • 집계 파이프라인(Aggregation Pipeline) — 가장 권장되는 방법이에요.
  • 단일 목적 집계 메서드(Single Purpose Aggregation Methods) — 집계 파이프라인보다 기능은 적지만, 컬렉션 단위로 간단히 쓰기 좋습니다.

MongoDB Atlas에 배포되어 있다면 UI에서도 집계 파이프라인을 바로 실행할 수 있습니다.

집계 파이프라인

집계 파이프라인은 문서를 처리하는 하나 이상의 단계(stage) 로 구성됩니다. 이 문서들은 컬렉션에서 오기도 하고, view에서 오거나, 특별히 설계된 단계가 만들어낸 결과일 수도 있어요.

각 단계는 입력으로 들어온 문서에 어떤 작업을 수행합니다. 예를 들어 어떤 단계는 문서를 $filter로 거르고, 다른 단계는 $group으로 묶고, 또 다른 단계는 값을 계산하죠. 그러면 그 단계가 출력한 문서들이 파이프라인에서 다음 단계로 전달됩니다.

집계 파이프라인은 문서 그룹에 대한 결과를 돌려줄 수도 있고, "Updates with Aggregation Pipeline"에서 보여주는 단계들을 이용해 문서 자체를 업데이트하는 데에도 쓸 수 있습니다.

참고 db.collection.aggregate() 메서드로 실행되는 집계 파이프라인은, 파이프라인에 $merge 또는 $out 단계가 포함되어 있지 않다면 컬렉션의 문서를 수정하지 않습니다.

집계 파이프라인 예시

이 페이지의 예시는 sample_mflix 샘플 데이터 세트의 영화 데이터를 사용합니다. 자체 관리형(셀프 매니지드) MongoDB 배포서버에 이 데이터 세트를 불러오는 방법은 "Load the sample dataset"에서 확인할 수 있고요, 샘플 데이터베이스를 건드렸다면 예시를 그대로 실행하기 위해 데이터베이스를 지우고 다시 만들어야 할 수도 있습니다.

다음 파이프라인은 데이터베이스에서 가장 많은 영화를 감독한 상위 3명의 감독을 찾아냅니다.

먼저 $match 단계로 감독이 등재된 영화만 남깁니다. 여기서는 directors 필드가 존재하고, null도 아니고, 빈 배열($size: 0)도 아닌 문서로 조건을 걸어요.

{
    $match : {
        "directors" : { $exists: true, $ne: null, $not: {$size: 0} }
    }
},

$match 단계는 감독 정보가 없는 영화를 걸러내, 뒤에서 처리할 문서 수를 줄여줍니다. 다음으로 $unwind를 써서 directors 배열을 분해합니다. 그래야 감독 한 명씩 따로 세어볼 수 있거든요.

{
    $unwind : "$directors"
},

이제 $group으로 문서를 감독 이름(_id)별로 묶고, 각 감독의 영화 수(movieCount)를 $sum: 1로 셉니다.

{
    $group : {
    _id : "$directors",
    movieCount : {
        $sum: 1
        }
    }
},

$sort를 쓰면 남은 문서를 영화 수(movieCount) 기준 내림차순으로 정렬합니다.

{
    $sort : {
        movieCount : -1
    }
},

마지막으로 $limit로 상위 3건만 남깁니다.

{
    $limit : 3
}

이 다섯 단계를 합친 전체 파이프라인은 이렇게 생겼어요.

db.movies.aggregate(
  [
    {
        $match : {
            "directors" : { $exists: true, $ne: null, $not: {$size: 0} }
        }
    },
    {
        $unwind : "$directors"
    },
    {
        $group : {
        _id : "$directors",
        movieCount : {
            $sum: 1
            }
        }
    },
    {
        $sort : {
            movieCount : -1
        }
    },
    {
        $limit : 3
    }
  ]
)

그리고 이 파이프라인이 돌려주는 결과입니다.

[
  { _id: 'Woody Allen', movieCount: 40 },
  { _id: 'Martin Scorsese', movieCount: 32 },
  { _id: 'Takashi Miike', movieCount: 31 }
]

샘플 입력 문서가 포함된 실행 가능한 예시는 "Complete Aggregation Pipeline Examples"에서 볼 수 있고, 집계 파이프라인의 더 자세한 내용은 "Aggregation Pipeline" 문서에서 다룹니다.

단일 목적 집계 메서드

단일 목적 집계 메서드는 하나의 컬렉션에서 문서를 집계합니다. 이 메서드들은 집계 파이프라인보다 기능이 적지만, 자주 쓰는 단순한 집계는 빠르게 해결해 줍니다.

메서드 설명
db.collection.estimatedDocumentCount() 컬렉션 또는 view에 있는 문서의 대략적인 개수를 반환합니다.
db.collection.count() 컬렉션 또는 view에 있는 문서의 개수를 반환합니다.
db.collection.distinct() 지정된 필드에 대해 고유한 값을 가진 문서의 배열을 반환합니다.