본문 바로가기
DataBase/NoSQL

[NoSQL] MongoDB 집계(Aggregation)1

by 스파이디웹 2021. 1. 21.
728x90

#집계 프레임워크

-파이프라인의 각 단계에서의 출력이 다음 단계로의 입력으로 제공되는 파이프라인(집계 파이프라인,aggregation pipeline)을 정의한다.

 

$project - 출력 도큐먼트상에 배치할 필드를 지정한다.(projected)

$match - 처리될 도큐먼트를 선택하는 것. find()와 비슷한 역할을 수행한다.

$limit - 다음 단계에 전달될 도큐먼트의 수를 제한한다.

$skip - 지정된 수의 도큐먼트를 건너뛴다.

$unwind -배열을 확장하여 각 배열 항목에 대해 하나의 출력 도큐먼트를 생성한다.

$group -지정된 키로 도큐먼트를 그룹화한다.

$sort -도큐먼트를 정렬한다.

$geoNear - 지리 공간위치 근처의 도큐먼트를 선택한다.

$out - 파이프라인의 결과(출력)를 컬렉션에 쓴다.

$redact -특정 데이터에 대한 접근을 제어한다.

 

ex)

db.컬렉션이름.aggregate([ {$match: ...}, {$group: ...}, {$sort: ...} ] )

 

1)전체 제품 컬렉션은 $match 작업으로 전달되고, 입력된 컬렉션으로부터 오직 특정 도큐먼트만 선택한다.

2)$match의 출력은 $group 연산자로 전달되며, $group 연산자는 출력을 특정 키로 그룹화하여 합계 및 평균과 같은 새로운 정보를 제공한다.

3)$group 연산자의 출력은 마지막 단계인 $sort 연산자로 전달되어 정렬이 수행되고 그 뒤에 최종 결과로 반환된다.

 

SQL vs 집계 프레임워크 비교

 

SQL 명령어 집계 프레임워크 연산자
SELECT $project
$group 함수 : $sum,$min,$avg 등
FROM db.collectionName.aggregate(. . .)
JOIN $unwind
WHERE $match
GROUP BY  $group
HAVING $match

$project- 처리할 도큐먼트의 필드를 지정한다.

ex)

db.uesrs.findOne(

   {username: 'kbanker',

    hashed_password: 'bd1cfa194c3a603e7186780824b04419'},

   {first_name:1, last_name:1} //이름과 성을 반환하는 프로젝션 개체

)

 

db.uesrs.aggregate([

   {$match: {username: 'kbanker',

    hashed_password: 'bd1cfa194c3a603e7186780824b04419'},

   {$project: {first_name:1, last_name:1}} //이름과 성을 반환하는 프로젝트 파이프라인 연산자

])

 

-많은 수의 도큐먼트 재형성(reshaping)기능을 사용할 수 있다.

 

$group- 지정된 키별로 도큐먼트를 그룹화한다.

-$group 연산자에 _id필드를 정의하여 도큐먼트를 그룹화하는 방법이 있다. $group 연산자는 입력된 도큐먼트를 지정된 _id 필드로 그룹화하여 각 도큐먼트 그룹에 대한 집계된 정보를 제공한다.

 

ex)

db.orders.aggregate([

   {$match: {purchase_data: {$gte: new Date(2010, 0 , 1}}},

   {$group: {

         _id: {year : {$year : '$purchase_date'},

                   month: {$month : '$purchase_date'}},

         count: {$sum: 1},

         total: {$sum: '$sub_total'}}},

   {$sort: {_id:-1}}

]);

 

result

{"_id : {"year" : 2014, "month" : 11},

 "count" : 1, "total" : 4897}

{"_id : {"year" : 2014, "month : 8},

 "count" : 2, "total" : 11093 }

...

-그룹의 _id 필드를 정의할 때 하나 이상의 기존 필드를 사용하거나 도큐먼트 재형성 기능 중 하나를 사용할 수 있다.

(이 예제는 $year,$month 재형성 함수의 활용을 보여준다.)

$group 함수
$addToSet 그룹에 고유한 값의 배열을 만든다
$first 그룹의 첫 번째 값. $sort를 선행해야만 의미가 있다.
$last 그룹의 마지막 값. $sort를 선행해야만 의미가 있다.
$max 그룹의 필드 최댓값
$min 그룹의 필드 최솟값
$avg 필드의 평균값
$sum 그룹의 모든 값의 배열을 반환한다. 중복값을 제거하지 않는다.
$sum 그룹의 모든 값의 합계

$match, $sort, $skip, $limit- 선택하고, 정렬하며,  건너뛰고,크기를 제한한다.

ex)

page_number = 1

product = db.products.findOne({'slug': '~~'})

 

reviews = db.reviews.find({'product_id': product['_id']}).

                            skip((page_number - 1) * 12).

                            limit(12).

                            sort({'helpful_votes': -1})

 

집계 프레임워크에서의 동일한 쿼리

reviews2 = db.reviews.aggregate([

           {$match: {'product_id': product['_id']}}},

           {$skip : (page_number - 1) * 12},

           {$limit: 12},

           {$sort: {'helpful_votes': -1}}

]).toArray();

 

$unwind -배열의 모든 항목에 대해 하나의 출력 도큐먼트를 생성하여 배열을 확장

ex)

db.products.findOne({},{category_ids:1})

{

  "_id" : ObjectId("~~"),

  "category_ids" : [

        ObjectId("~~"),

        ObjectId("~~")

     ]

}

db. productts.aggregate([

    {$project : {category_ids:1}},

    {$unwind : '$category_ids'},

    {$limit : 2}

  ]);

 

result

{ "_id" : ObjectId("~~"),

  "category_ids" : ObjectId("~~48") }

{ "_id" : ObjectId("~~"),

  "category_ids" : ObjectId("~~49") }

 

$out - 파이프라인의 결과를 컬렉션에 기록한다

db.orders.aggregate([

   {$match: upperManhattanOrders},

   {$group: sumByUserId},

   {$match: orderTotalLarge},

   {$sort: sortTotalDesc},

   {$out: 'targetedCustomers'}

]);


#도큐먼트 재구성(reshape)

ex)

first 와 last name을 name이라는 하위객체를 만들어서 사용

db.users.aggregate([

   {$match: {username: 'kbanker'}},

   {$project: {name: {first:'$first_name',

                          last:'$last_name'}}

   }

])

->

{ "_id" : ObjectId("~~"),

  "name" : {"first" : "kyle",

               "last" : "banker"}

}

문자열 함수

문자열
$concat 두 개 이상의 문자열을 단일 문자열로 연결한다
$strcasecmp 대/소문자를 구분하지 않는 문자열 비교를 하며,숫자를 반환한다
$substrBytes 문자열의 부분 문자열을 만든다
$toLower 문자열을 모두 소문자로 변환한다
$toUpper 문자열을 모두 대문자로 변환한다

산술 함수

산술
$add 배열 번호를 추가한다
$divide 첫 번째 숫자를 두 번째 숫자로 나눈다
$mod 첫 번째 숫자의 나머지를 두 번째 숫자로 나눈다
$multiply 숫자 배열을 곱한다
$subtract 첫 번째 숫자에서 두 번째 숫자를 뺀다

날짜/시간 함수

 

날짜/시간
$dayOfYear 연 중의 일로서 1에서 366까지다
$dayOfMonth 월 중의 일로서 1에서 31까지다
$dayOfWeek 주 중의 일로서 1에서 7까지이며,1은 일요일을 의미한다
$year 날짜의 연 부분이다
$month 날짜의 월 부분으로 1에서 12까지다
$week 연 중의 주 로서, 0에서 53까지다
$hour 시간을 뜻하고, 0에서 23까지다
$minute 분을 뜻하고, 0에서 59까지다
$second 초를 뜻하고, 0에서 59까지다(윤초는 60초)
$millisecond 시간 중 밀리초를 뜻하며, 0에서 999까지다

논리 함수

논리
$and 배열 내의 모든 값이 true의 경우는 true
$cmp 두 개 값을 비교하여 결괏값을 반환해 주며, 두 값이 동일하면 0을 반환한다
$cond if...then...else 조건부 논리 x?y: z 삼항연산자와 유사
$eq 두 값이 동일한지의 여부 확인
$gt 하나의 값이 다른 하나의 값보다 큰지의 여부 확인
$gte 하나의 값이 다른 하나의 값보다 크거나 같은지의 여부 확인
$ifNull null값/표현식을 지정된 값으로 변환한다
$lt 하나의 값이 다른 하나의 값보다 작은지의 여부 확인
$lte 하나의 값이 다른 하나의 값보다 작거나 같은지의 여부 확인
$ne 두 값이 동일하지 않은지에 대한 여부 확인
$not 주어진 값의 반대 조건을 반환한다. 값이 true면 false, flase이면 true
$or 배열의 값 중 그 어떤 하나라도 ture인 경우 true

집합 함수

집합
$setEquals 두 개의 집합이 완전히 같은 요소를 가지는 경우 true
$setIntersection 두 개의 집합에서 공통적으로 존재하는 요소의 배열을 반환한다
$setDifference 두 번째 집합에 없는 첫 번째 집합의 요소를 반환한다
$setUnion 두 집합의 합집합을 반환한다
$setIsSubset 두 번째 집합이 첫 번째 집합의 부분집합이면 true
(두 번째 집합의 모든 요소도 첫 번째 집합의 부분집합)
$anyElementTrue 집합의 요소 중 그 어느 하나라도 true이면 true
$allElementTrue 집합의 모든 요소가 true일 경우에만 true
$not 주어진 값의 반대 조건을 반환한다.값이 true이면 false,flase이면 true
$or 배열의 값 중 그 어떤 하나라도 true인 경우는 true

 

기타 함수

 

기타
$meta 텍스트 검색 관련 정보에 접근한다.
$size 배열의 크기를 반환한다
$map 배열의 각 멤버에 표현식(expression)을 적용한다
$let 표현식의 범위 내에서 사용되는 변수를 정의한다
$literal 표현식의 값을 평가하지 않고 반환한다

 

728x90

댓글