Aggregation Pipeline 복습
MongoDB의 Aggregation Pipeline은 문서를 단계별로 변환하는 데이터 처리 파이프라인입니다. $facet은 하나의 파이프라인에서 여러 집계를 동시에 수행하고, $bucket은 데이터를 범위별로 그룹화하는 강력한 스테이지입니다.
$facet — 다차원 집계
db.products.aggregate([
{ $match: { status: "active" } },
{ $facet: {
results: [
{ $sort: { createdAt: -1 } },
{ $skip: 0 },
{ $limit: 20 },
{ $project: { name: 1, price: 1, category: 1, rating: 1 } }
],
categoryFacet: [
{ $group: { _id: "$category", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
],
brandFacet: [
{ $group: { _id: "$brand", count: { $sum: 1 } } },
{ $sort: { count: -1 } },
{ $limit: 20 }
],
priceStats: [
{ $group: {
_id: null,
avgPrice: { $avg: "$price" },
minPrice: { $min: "$price" },
maxPrice: { $max: "$price" },
totalProducts: { $sum: 1 }
}}
],
ratingDistribution: [
{ $group: {
_id: { $floor: "$rating" },
count: { $sum: 1 }
}},
{ $sort: { _id: -1 } }
]
}}
]);
$bucket — 범위 기반 그룹화
db.products.aggregate([
{ $bucket: {
groupBy: "$price",
boundaries: [0, 10000, 30000, 50000, 100000, 500000, Infinity],
default: "기타",
output: {
count: { $sum: 1 },
avgPrice: { $avg: "$price" },
brands: { $addToSet: "$brand" },
products: { $push: { name: "$name", price: "$price" } }
}
}}
]);
$bucketAuto — 자동 범위 설정
db.users.aggregate([
{ $bucketAuto: {
groupBy: "$totalPurchases",
buckets: 5,
granularity: "R5",
output: {
count: { $sum: 1 },
avgSpent: { $avg: "$totalSpent" },
users: { $push: "$name" }
}
}}
]);
db.orders.aggregate([
{ $addFields: {
hour: { $hour: "$createdAt" }
}},
{ $bucket: {
groupBy: "$hour",
boundaries: [0, 6, 12, 18, 24],
default: "unknown",
output: {
orderCount: { $sum: 1 },
totalRevenue: { $sum: "$total" },
avgOrderValue: { $avg: "$total" }
}
}}
]);
실전: 대시보드 데이터 한 번에 조회
db.orders.aggregate([
{ $match: {
createdAt: {
$gte: ISODate("2024-01-01"),
$lt: ISODate("2025-01-01")
}
}},
{ $facet: {
monthlySales: [
{ $group: {
_id: { $dateToString: { format: "%Y-%m", date: "$createdAt" } },
revenue: { $sum: "$total" },
orders: { $sum: 1 }
}},
{ $sort: { _id: 1 } }
],
topCategories: [
{ $unwind: "$items" },
{ $group: {
_id: "$items.category",
revenue: { $sum: { $multiply: ["$items.price", "$items.quantity"] } }
}},
{ $sort: { revenue: -1 } },
{ $limit: 5 }
],
statusBreakdown: [
{ $group: { _id: "$status", count: { $sum: 1 } } }
]
}}
]);
성능 최적화 팁
$facet앞에$match를 배치하여 처리 대상 문서를 먼저 줄입니다- 각 facet 파이프라인은 독립적으로 실행되므로, RAM 사용량에 주의합니다 (100MB 제한)
allowDiskUse: true옵션으로 메모리 제한을 우회할 수 있습니다$bucket의boundaries는 반드시 오름차순이어야 합니다$bucketAuto의granularity옵션(R5, R10, E6 등)으로 경계값을 깔끔하게 만듭니다
댓글 0