본문 바로가기

DB/MongoDB

[MongoDB] 14. 집계명령어 - 고급 스테이지, 여러가지 스테이지

728x90
반응형

누산기(accumulator) 객체

여러 도큐먼트에서 찾은 필드로 부터 값을 "계산"하는 객체이다.
MongoDB 3.2 이전에는 $group 스테이지에서만 누산기 객체를 사용했지만, 이후에는 $project 스테이지에서도 배열안에서 작동한다.

원본

// 컬렉션 rating
db.rating.find()

$max

  • 그룹에서 해당 필드의 최댓값을 반환
db.rating.aggregate([
    {
        $group:{"_id":"$rating","max_user_id":{$max:"$user_id"}}
    }
])

$min

  • 그룹 필드에서 해당 필드의 최솟값을 반환
db.rating.aggregate([
    {
        $group:{"_id":"$rating","min_user_id":{$min:"$user_id"}}
    }
])

$sum

  • 그룹에서 해당 필드의 합산값을 반환
db.rating.aggregate([
    {
        $group:{"_id":"$rating",sum_user_id":{$sum:"$user_id"}}
    }
])

$avg

  • 그룹에서 해당 필드의 평균값을 반환
db.rating.aggregate([
    {
        $group:{"_id":"$rating","avg_user_id":{$avg:"$user_id"}}
    }
])

$project 단계에서 사용된 누산기

db.array.find()
db.array.aggregate([
	{
    	$project : {_id:0,"max_len_array":{$max:"$doc"}}
    }
])

$unwind 스테이지

하나의 도큐먼트에 있는 배열 요소들을 분리하여 각각 도큐먼트에 분배하는 역할(카티션 곱 기능)
$push의 반대 기능
{키1 : "값1",키2 : "값2",키3 : ["요소1","요소2","요소3"]}
$unwind => {키1 : "값1",키2 : "값2",키3:"요소1"} {키1 : "값1",키2 : "값2",키3:"요소2"} {키1 : "값1",키2 : "값2",키3:"요소3"}

$unwind 전

db.rating.aggregate([
	{
		$match:{rating:{$gte:4}}
	},
    {
		$group : {_id:"$rating",user_ids:{$push:"$user_id"}}
    }
])

$unwind 후

db.rating.aggregate([
	{
		$match:{rating:{$gte:4}}
	},
    {
		$group : {_id:"$rating",user_ids:{$push:"$user_id"}}
    },
    {
    	$unwind : "$user_ids"
    }
])

$out 스테이지

입력 받은 도큐먼트를 컬렉션으로 저장
컬렉션에 저장하지 않으면 콘솔에 출력되는 것으로 질이는 끝난다.

db.rating.aggregate([
	{
    	$group:{_id:"$rating",user_ids:{$push:"$user_id"}}
    },
    {
    	$out:"user_id_by_rating"
    }
])

$sort 스테이지

요소를 정렬한다.

db.rating.aggregate([
	{
		$sort : {"user_id":-1}
	}
])
// -1 내림차순, 1 오름차순

$skip 스테이지

출력을 입력 한 숫자 만큼 넘어간다.

db.rating.aggregate([
    {
    	$sort : {"rating":1}
    },
    {
		$skip: 5
    }
])

$limit 스테이지

출력되는 도큐먼트 개수를 입력한 숫자 만큼 제한 한다.

db.rating.aggregate([
    {
    	$sort : {"rating":1}
    },
    {
		$limit: 5
    }
])

고급 스테이지

스테이지 설명
$bucket 도큐먼트를 범위에 따라 그룹화 한다.
- $group 스테이지는 유니크한 모든 값에 대해서 그룹 생성
- $bucket은 사용자가 임의로 각 그룹의 범위를 설정 가능
$bucketAuto 자동 그룹핑(그룹의 갯수에 따라)
$addFields $project 스테이지에서 새로운 필드 추가
$facet 각 필드에 대한 서브 파이프라인 수행해서 배열로 저장
$lookup 같은 DB에 있으면서 샤딩되지 않은 외부 컬렉션에 대해, 현재 필드와 외부 필드가 일치하면 배열로 외부 컬렉션 도큐먼트를 가져옴.
(Join 연산과 유사함.)


$bucket 스테이지

$bucket: 
    { 
        groupBy: <expression>, // 버케팅 할 기준
        boundaries: [ <lowerbound1>, <lowerbound2>, ... ], // 버케팅 기준값의 구간
        default: <literal>, // optional. 구간 외의 도큐먼트를 처리할 필드명
        output: { 
            <output1>: { <$accumulator expression> }, 
            // optional. 버케팅한 후 출력 결과를 표시할 방법 ... 
            <outputN>: { <$accumulator expression> } 
    	} 
	}
db.rating.aggregate([
	{
    	$bucket:{
        	groupBy:"$rating",
        	boundaries:[2,3,5],
        	default:"Others",
        	output : {
        		count : {$sum : 1},
        		user_ids : {$push: "$user_id"}
            }
        }
    }
])


$bucketAuto 스테이지

  • 범위를 자동으로 설정
  • 전체 도큐먼트를 몇 개의 그룹으로 묶을지 설정하면, 그룹에 따라 자동으로 그룹을 실행
$bucketAuto: {
	groupBy: 그룹핑 기준,
    buckets : 버킷 사이즈, 필수 속성 // default 대신
    output:{...}
}
granularity : //boundaries 대신
db.rating.aggregate([
	{
    	$facet:{
        	categorizedRating : [
            {$group : {_id:"$rating",count : {$sum:1}}}
            ],
            "categorizedById(Auto)":[
            {$bucketAuto : {groupBy:"$_id",buckets:5}}
            ]
        }
    }
])


$addFields 스테이지

db.rating.aggregate([
	{
    	$addFields:{
        	hello:"world"
        }
    },
    {$project : {hello:1}},
    {$limit:4}
])

$facet 스테이지

  • 하나의 쿼리로 다양한 기준의 그룹핑을 수행할 때 사용
  • 카테고리별로 그룹핑하는 작업을 하나의 질의로 해결하려고 할 때
  • 하나의 쿼리에 여러 개의 파이프라인({})을 나열해서 한 번의 여러 기준의 그룹핑을 수행할 수 있다.
{ 
	$facet:
    {
        <outputField1>: [ <stage1>, <stage2>, ... ],
        <outputField2>: [ <stage1>, <stage2>, ... ],
        ...	
    }
}

// outputField는 서프 파이프라인이라고 하고 
// $bucket, $bucketAuto, $sortByCount 중 하나의 서브 스테이지를 반드시 가져야한다.
db.rating.aggregate([
	{
    	$facet:{
        	categorizedRating:[
            	{$group : {_id:"$rating",count:{$sum:1}}}
            ],
            "categorizedById(Auto)" : [
            	{$bucketAuto:{groupBy:"$_id",buckets:5}}
            ]
        }
    }
])

$lookup 스테이지
https://github.com/Karoid/mongodb_tutorials - 실습 데이터

  • 첫번째 형식
    • from : 조인할 도큐먼트 결정
    • localField : 넘겨받은 도큐먼트의 어떤 필드를 from에서 정한 도큐먼트의 필드와 매칭할지 결정
    • foreignField : from에서 선택한 도큐먼트에서 어떤 필드를 localField에서 정한 필드와 매칭할 지 결정
    • as : from에서 정한 도큐먼트로부터 매칭되어 가져온 데이터를 여기서 정한 데이터 필드의 배열 안에 넣음
  • 두번째 형식
    • pipline : from에서 설정한 컬렉션을 해당 파이프라인에 통과시킨 뒤, 출력되는 도큐먼트들을 as에서 정한 필드에 배열 요소로 연결 
    • let : 선택적, pipeline 파라미터에 현재 넘겨 받은 도큐먼트의 값을 비교, 대조해야할 필요성, pipeline 파라미터에 현재 도큐먼트 값을 넘길 수 있도록 변수 선언
db.by_month.aggregate([
	{
		$lookup:
		{
			from : "area",
			localField : "area_id",
			foreignField : "_id",
			as : "area_data"
		}
	},
	{$limit : 1}
])

- 두번째 형식 -

db.orders.aggregate([
	{
		$lookup:
		{
			from : "warehouse",
			let : {order_item : "$item",order_qty:"$ordered"},
			pipeline: [
			{$match:
			   {$expr:
			     {$and:
				[
				{$eq:["$stock_item","$$order_item"]},
				{$gte: ["$instock","$$order_qty"]}
				]
			     }
			   }
			},
			{$project : {stock_item:0, _id:0}}
			] ,
			as : "stockdata"
		}
	}
])
  • pipeline 파라미터
    • warehouses 컬렉션에서 주어진 조건에 맞는 도큐먼트만 남기게 만든다.
    • stockdata 필드의 배열에 결과를 출력
  • let에서 order_item과 order_qty로 설정한 두 개의 변수는 $$를 붙혀 pipeline 파라미터에서 비교에 사용됨.

$replaceRoot 스테이지

  • $project 스테이지와 유사하게 도큐먼트의 모양을 바꾸는 스테이지
  • 서브 도큐먼트를 도큐먼트 전체의 내용으로 바꿀 때 유용함.
db.by_month.aggregate([
	{
    	$addFields:{
        	"month_data.city_or_province":"$city_or_province",
            "month_data.country":"$county"
        }
    },
    {
    	$replaceRoot: {newRoot:{$arrayElemAt : ["$month_data",0]}}
    }
])

기존의 month_data의 값에 지역정보(city_or_province, country)가 같이 출력됨.

$sample 스테이지

  • 주어진 도큐먼트들을 랜덤하게 정해진 수대로 고르고자 할 때 사용함.
  • 도큐먼트 중 몇 개의 샘플을 고르는 스테이지
db.rating.aggregate([
	{
    	$sample:{size:3}
    }
])

$sortByCount 스테이지

  1. 주어진 필드의 값이 같은 도큐먼트들 끼리 그룹화
  2. 도큐먼트의 숫자를 셈
  3. 내림 차순 정렬
db.rating.aggregate([{$sortByCount:"$rating"}])

728x90
반응형