집계 연산 개요
MongoDB 집계 연산은 다중 문서의 데이터를 처리해 계산 결과를 반환합니다. 문서 그룹을 대상으로 다양한 연산을 수행하며, 단일 목적 집계, 파이프라인 집계, MapReduce 세 가지 유형으로 구분됩니다.
- 단일 목적 집계: 단일 컬렉션 대상의 기본 집계 함수 제공
- 파이프라인 집계: 다단계 데이터 처리 모델 기반의 유연한 프레임워크
- MapReduce: 대용량 데이터 분산 처리용 2단계 연산 모델
단일 목적 집계
db.collection.estimatedDocumentCount(), db.collection.count(), db.collection.distinct() 함수로 기본 집계 수행. 파이프라인에 비해 기능 제한적입니다.
| 연산 | 기능 |
|---|---|
| estimatedDocumentCount() | 컬렉션 전체 문서 수 추정 |
| count() | 쿼리 매칭 문서 수 계산 |
| distinct() | 필드 고유값 배열 반환 |
// 상품 컬렉션 문서 수
db.products.estimatedDocumentCount()
// 좋아요 50개 초과 문서 수
db.products.count({likes:{$gt:50}})
// 카테고리 고유값
db.products.distinct("category")
// 좋아요 90개 초과 상품의 카테고리
db.products.distinct("category",{likes:{$gt:90}})
샤딩 환경에선 db.collection.aggregate() 사용을 권장합니다.
집계 파이프라인
파이프라인 구조
다단계(stage) 처리 모델로 문서를 순차적 변환합니다.
pipeline = [$stage1, $stage2, ...$stageN];
db.collection.aggregate(pipeline, {options})
주요 파이프라인 단계
| 단계 | 기능 | SQL 유사 연산 |
|---|---|---|
| $match | 필터링 | WHERE |
| $project | 필드 선택/변환 | SELECT |
| $lookup | 조인 | LEFT JOIN |
| $group | 그룹화 | GROUP BY |
| $unwind | 배열 해체 | - |
데이터 준비
const tags = ["db","nosql","cloud","dev","popular"];
const types = ["tech","social","travel","fiction","science"];
let products = [];
for(let i=0; i<50; i++){
const typeIdx = Math.floor(Math.random()*types.length);
const tagIdx = Math.floor(Math.random()*tags.length);
const likes = Math.floor(Math.random()*100);
const creator = "user" + Math.floor(Math.random()*10);
products.push({
name: "product-"+i,
type: types[typeIdx],
tags: [tags[tagIdx]],
likes: likes,
creator: { id: creator }
})
}
db.products.insertMany(products);
$project 예제
// 필드 이름 변경
db.products.aggregate([{$project:{title:"$name"}}])
// 중첩 문서 필드 선택
db.products.aggregate([
{$project:{name:1, "creator.id":1}}
])
$match + $project 결합
db.products.aggregate([
{$match:{type:"tech"}},
{$project:{_id:0, name:1, type:1}}
])
$group 연산
// 제작자별 좋아요 합계
db.products.aggregate([
{$group:{_id:"$creator.id", totalLikes:{$sum:"$likes"}}}
])
// 제작자별 상품 유형 집합
db.products.aggregate([
{$group:{_id:"$creator.id", types:{$addToSet:"$type"}}}
])
$unwind 활용
// 태그 배열 분해
db.products.aggregate([
{$unwind:"$tags"},
{$group:{_id:"$creator.id", uniqueTags:{$addToSet:"$tags"}}}
])
$lookup 조인 예제
// 주문-고객 조인
db.orders.aggregate([
{$lookup:{
from: "clients",
localField: "clientId",
foreignField: "id",
as: "clientInfo"
}}
])
집계 사례
카테고리별 상품 수
db.products.aggregate([
{$group:{_id:"$type", count:{$sum:1}}},
{$sort:{count:-1}}
])
태그 인기 순위
db.products.aggregate([
{$match:{likes:{$gt:0}}},
{$unwind:"$tags"},
{$group:{_id:"$tags", popularity:{$sum:"$likes"}}},
{$sort:{popularity:-1}}
])
MapReduce 연산
db.products.mapReduce(
function(){emit(this.type, this.likes)},
function(key,values){return Array.sum(values)},
{query:{type:"travel"}, out:"results"}
)
MongoDB 5.0+부터는 집계 파이프라인 사용을 권장합니다.