몽고디비 인 액션 6장 -1

집계

MongoDB 집계 프레임워크를 사용하여 보다 복잡한 쿼리 사용을 알아본다. (예. 월별매출, 제품별 매출, 사용자별 주문합계 등, cf. GROUP BY)

집계 프레임워크 개요

  • 집계 파이프라인
    • $project : 출력 도큐먼트상에 배치할 필드 지정
    • $match : 처리될 도큐먼트를 선택하는 것. (= find())
    • $limit : 다음 단계에 전달될 도큐먼트의 수 제한
    • $skip : 지정된 수의 도큐먼트를 건너뛴다.
    • $unwind : 배열을 확장하여 각 배열 항목에 대해 하나의 출력 도큐먼트 생성
    • $group : 지정된 키로 도큐먼트를 그룹화
    • $sort : 도큐먼트 정렬
    • $geoNear : 지리 공간위치 근처의 도큐먼트 선택
    • $out : 파이프라인의 결과를 컬렉션에 쓴다
    • $redact : 특정 데이터에 대한 접근을 제어
db.products.aggregate([{$match: ...}, {$group: ...}, {$sort: ...} ] )

-> match, group, sort로 구성된 집계 프레임워크 파이프라인

전체 제품컬렉션 -> $match 작업으로 전달 -> $group 연산자로 전달 (특정 키로 그룹화하여 합계 및 평균과 같은 정보제공) -> $sort 연산자로 전달 (정렬 수행)

전자상거래 집계 예제

제품 : 리뷰 = 1 : n
  • 상품, 카테고리, 리뷰
product = db.products.findOne({'slug':'wheelbarrow-9092'})
reviews_count = db.reviews.count({'product_id':product['_id']})

제품의 리뷰수 계산 예시 (5장내용)

db.reviews.aggregate([
 {$group : { _id:'$product_id', // product_id로 입력 도큐먼트를 그룹화
 count:{$sum:1} }}               // 각 제품에 대한 리뷰수를 카운트
]);

// 각 제품에 대해 하나의 도큐먼트를 출력
{ "_id" : ObjectId("4c4b1...82"), "count" : 2 } 
{ "_id" : ObjectId("4c4b1...81"), "count" : 3 }
//관심상품 한개에 대한 리뷰수 카운트
product = db.products.findOne({'slug': 'wheelbarrow-9092'})
ratingSummary = db.reviews.aggregate([ 
 {$match : { product_id: product['_id']} }, // 하나의 상품 선택
 {$group : { _id:'$product_id',               // 결과의 첫 번째 도큐먼트를 반환
 count:{$sum:1} }}
]).next(); 

{ "_id" : ObjectId("4c4b1...81"), "count" : 3 }
db.reviews.count({'product_id': product['_id']})

$match를 $group 앞에 두어야 처리해야하는 도큐먼트를 수를 줄이면서 연산할 수 있다.

  • 평균 리뷰 계산하기
product = db.products.findOne({'slug': 'wheelbarrow-9092'})
ratingSummary = db.reviews.aggregate([
 {$match : {'product_id': product['_id']}},
 {$group : { _id:'$product_id',
 average:{$avg:'$rating'},                            // 제품의 평균 평점을 계산
 count: {$sum:1}}}
]).next();

{
 "_id" : ObjectId("4c4b1476238d3b4dd5003981"),
 "average" : 4.333333333333333,
 "count" : 3
} 
  • 등급별 리뷰 계산하기
제품에 대해 5명 리뷰어가 5점 , 2명이 4점, 1명이 3점
countsByRating = db.reviews.aggregate([
 {$match : {'product_id': product['_id']}},    // 제품선택
 {$group : { _id:'$rating',                       // 등급별로 그룹화 ($rating)
 count:{$sum:1}}}                                // 각 등급별 리뷰수 계산
]).toArray();                                       // 결과 커서를 배열로 변환


[ { "_id" : 5, "count" : 5 },
 { "_id" : 4, "count" : 2 },
 { "_id" : 3, "count" : 1 } ]
SELECT RATING, COUNT(*) AS COUNT
FROM REVIEWS
WHERE PRODUCT_ID = '4c4b1476238d3b4dd5003981'
GROUP BY RATING

SQL 쿼리

  • 컬렉션 조인
db.products.aggregate([
 {$group : { _id:'$main_cat_id',
 count:{$sum:1}}}
]);

{ "_id" : ObjectId("6a5b1476238d3b4dd5000048"), "count" : 2 }
db.mainCategorySummary.remove({}); // mainCategorySummary 컬렉션에서 기존 도큐먼트를 제거

db.products.aggregate([
 {$group : { _id:'$main_cat_id',
 count:{$sum:1}}}
]).forEach(function(doc){
 var category = db.categories.findOne({_id:doc._id});        //결과에 대한 카테고리 읽기
 if (category !== null) {                                             // 카테고리가 없을 때      
 doc.category_name = category.name;
 }
 else {
 doc.category_name = 'not found';
 }
 db.mainCategorySummary.insert(doc);                         // 결합된 결과를 요약 컬렉션에 삽입
})

Leave a Comment