집계
1.도큐먼트 재구성
- 집계 파이프라인은 도큐먼트를 변형하여 출력 도큐먼트를 생성하는데 사용할 수 있는 다양한 함수 제공
1.1 문자열 함수
- $concat : 두 개 이상의 문자열을 단일 문자열로 연결
- $strcasecmp : 대/소문자를 구분하지 않는 문자열 비교를 하며, 숫자를 반환
- $substr : 문자열의 부분 문자열 반환
- $toLower : 문자열을 모두 소문자로 변환
- $toUpeer : 문자열을 모두 대문자로 변환
- 예시
db.users.aggregate([
{$match: {username: 'kbanker'}},
{$project:
{
name: {$concat:['$first_name', ' ', '$last_name']}, // 공백으로 연결
firstInitial: {$substr: ['$first_name',0,1]}, // 첫 번째 문자 반환
usernameUpperCase: {$toUpper: '$username'} // 대문자로 변경
}
}
])
// 결과
{
"_id" : ObjectId("4c4b1476238d3b4dd5000001"),
"name" : "Kyle Banker",
"firstInitial" : "K",
"usernameUpperCase" : "KBANKER"
}
1.2 산술 함수
- $add : 배열 번호를 추가
- $divide : 첫 번째 숫자를 두 번째 숫자로 나눈 값
- $mod : 첫 번째 숫자의 나머지를 두 번째 숫자로 나눈 값
- $multiply : 숫자 배열을 곱셈
- $subtract : 첫 번째 숫자에서 두 번째 숫자를 뺀 값
1.3 날짜/시간 함수
- $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까지
1.4 논리 함수
- $and : 배열 내의 모든 값이 true의 경우는 true
- $cmp : 두 개 값을 비교하여 결과값을 반환해 주며, 두 값이 동일하면 0을 반환
- $cond : if .. then .. else 조건부 논리
- $gt : 하나의 값이 다른 하나의 값보다 큰지의 여부 확인
- $gte : 하나의 값이 다른 하나의 값보다 크거나 같은지의 여부 확인
- $ifNull : null값/표현식을 지정된 값으로 변환
- $lt : 하나의 값이 다른 하나의 값보다 작은지의 여부 확인
- $lte : 하나의 값이 다른 하나의 값보다 작거나 같은지의 여부 확인
- $eq : 두 값이 동일한지의 여부 확인
- $ne : 두 값이 동일하지 않은지에 대한 여부 확인
- $not : 주어진 값의 반대 조건을 반환. true -> false
- $or : 배열의 값 중 그 어떤 하나라도 true 인 경우는 true
1.5 집합(Set) 함수
- $setEquals : 두 개의 집합이 완전히 같은 요소를 가지는 경우 true
- $setIntersection : 두 개의 집합에서 공통적으로 존재하는 요소의 배열을 반환. 교집합
- $setDifference : 두 번째 집합에서 없는 첫 번째 집합의 요소를 반환. 차집합
- $setUnion : 두 집합의 합집합을 반환
- $setIsSubset : 두 번째 집합이 첫 번째 집합의 부분집합이면 true
- $anyElementTrue : 집합의 요소 중 그 어느 하나라도 true 이면 true
- $allElementTrue : 집합의 모든 요소가 true일 경우에만 true
- $not : 주어진 값의 반대 조건을 반환. true -> false
- $or : 배열의 값 중 그 어떤 하나라도 true 인 경우 true
- 예시
// 샘플 도큐먼트 2건
{
"_id" : ObjectId("4c4b1476238d3b4dd5003981"),
"productName" : "Extra Large Wheel Barrow",
"tags" : [ "tools", "gardening", "soil" ]
}
{
"_id" : ObjectId("4c4b1476238d3b4dd5003982"),
"productName" : "Rubberized Work Glove, Black",
"tags" : [ "gardening" ]
}
// 실행
testSet1 = ['tools']
db.products.aggregate([
{
$project: {
productName: '$name',
tags:1,
setUnion: {$setUnion:['$tags',testSet1]}, // testSet1을 포함한 합집합
}
}
])
// 결과
{
"_id" : ObjectId("4c4b1476238d3b4dd5003981"),
"productName" : "Extra Large Wheel Barrow",
"tags" : ["tools", "gardening", "soil"],
"setUnion" : ["gardening","tools","soil"] // 합집합 결과
}
{
"_id" : ObjectId("4c4b1476238d3b4dd5003982"),
"productName" : "Rubberized Work Glove, Black",
"tags" : ["gardening"],
"setUnion" : ["tools", "gardening"] // 합집합 결과
}
1.6 기타 함수
- $meta : 텍스트 검색 관련 정보에 접근
- $size : 배열의 크기를 반환
- $map : 배열의 각 멤버에 표현식(expression)을 적용
- $let : 표현식의 범위 내에서 사용되는 변수 정의
- $literal : 표현식의 값을 평가하지 않고 반환
2. 집계 파이프라인 성능에 대한 이해
- 성능에 중요한 영향을 미칠 수 있는 주요 고려사항
- 파이프라인에서 간으한 한 빨리 도큐먼트의 수와 크기를 줄인다
- 인덱스는 $match와 $sort 작업에서만 사용할 수 있고, 이러한 작업은 크게 가속화할 수 있다.
- $match 또는 $sort 이외의 연산자를 파이프라인에서 사용한 후에는 인덱스를 사용할 수 없다.
- sharding을 사용하는 경우(매우 큰 컬렉션의 경우 일반적인 방법) $match 및 $project 연산자는 개별 샤드에서 실행된다. 다른 연산자를 사용하면 남아 있는 파이프라인이 프라이머리 샤드에서 실행된다.
2.1 집계 파이프라인 옵션
- aggregate 함수에 전달 할 수 있는 두 번째 매개 변수
- explain() : 파이프라인을 실행하고 오직 파이프라인 프로세스 세부 정보만 반환
- allowDiskUse : 중간 결과를 위해 디스크를 사용
- cursor : 초기 배치 크기를 지정
- 사용 예시
// 변수 선언
additionalOptions = {
explain: true,
allowDiskUse: true,
cursor: { batchSize: n }
};
// 파라미터 전달
db.collection.aggregate(pipeline, additionalOptions);
2.2 집계 파이프라인의 explain() 함수
- SQL에서 볼 수 있는 EXPLAIN 함수와 유사한 함수
- 파이프라인의 각 연산에 대한 explain 결과 반환
- MongoDB 서버 버전에 따라 explain() 함수의 결과가 다를 수 있음
- 예시
// 실행
> countsByRating = db.reviews.aggregate([
... {$match : {'product_id': product['_id']}}, // $match 먼저 실행
... {$group : { _id:'$rating',
... count:{$sum:1}}}
... ], {explain:true}); // explain 옵션 true
// 결과
// 인덱스 사용 여부 확인
// 인덱스 내 범위 스캔 여부 확인
{
"stages" : [
{
"$cursor" : {
"query" : {
"product_id" : ObjectId("4c4b1476238d3b4dd5003981")
},
"fields" : {
"rating" : 1,
"_id" : 0
},
"plan" : {
"cursor" : "BtreeCursor ", // 인덱스 기반 커서인
"isMultiKey" : false, // BTreeCursor 사용
"scanAndOrder" : false,
"indexBounds" : {
"product_id" : [ // 단위 제품에 사용되는 범위
[
ObjectId("4c4b1476238d3b4dd5003981"),
ObjectId("4c4b1476238d3b4dd5003981")
]
]
},
"allPlans" : [
...
]
}
}
},
{
"$group" : {
"_id" : "$rating",
"count" : {
"$sum" : {
"$const" : 1
}
}
}
}
],
"ok" : 1
}
2.3 allowDiskUse 옵션
- MongoDB는 블로킹 정렬 작업을 처리하는 동안 디스크의 임시 파일을 사용하여 100MB 시스템 메모리 제한을 초과하는 데이터를 저장 가능
- allowDiskUse 옵션을 true로 사용해야 가능
- allowDiskUse 옵션이 없다면 100MB 시스템 메모리 제한에 걸려서 에러 발생
2.4 집계 커서 옵션
- v2.6부터는 Mongo 셸을 통해 MongoDB에 엑세스하는 경우 기본값은 커서를 반환
- 기존 프로그램 손상 방지를 위해 파이프라인의 경우 예전과 같이 16MB로 제한된 단일 도큐먼트만 반환
- 옵션을 추가하여 결과를 커서로 반환 가능
- 예시
countsByRating = db.reviews.aggregate([
{$match : {'product_id': product['_id']}},
{$group : { _id:'$rating',
count:{$sum:1}}}
],{cursor:{}}); // 커서 반환
- 집계 파이프라인에서 반환된 커서의 지원 메소드
- cursor.hasNext() : 결과에 다음 도큐먼트가 존재하는지 확인
- cursor.nex() : 결과에서 다음 도큐먼트를 반환
- cursor.toArray() : 전체 결과를 배열로 반환
- cursor.forEach() : 결과의 각 행에 대해 함수 실행
- cursor.map() : 결과의 각 행에 대해 함수를 실행하고, 함수 반환값의 배열 반환
- cursor.itcount() : 항목수를 반환(테스트 전용)
- cursor.pretty() : 형식을 갖춘 결과의 배열을 표시
- cursor.objsLeftInBatch() : 현재 배치에 남아 있는 문서 수를 반환
- 커서의 목적은 많은 양의 데이터를 스트리밍할 수 있게 해주는 것으로 메모리 관리에 장점
3. 기타 집계 기능
3.1 .count()와 .distinct()
- count
- db.collection.count(query, options)
- distinct
- db.collection.distinct(field, query, options)
출처