참고
맵 리듀스의 대안으로서의 집계 파이프라인
MongoDB 5.0 부터 맵 리듀스 는 더 이상 사용되지 않습니다.
맵 리듀스 대신 집계 파이프라인을 사용해야 합니다. 집계 파이프라인은 맵 리듀스보다 성능과 유용성 측면에서 더 우수합니다.
4}
$group$merge, 등과 같은 집계 파이프라인 단계를 사용하여 맵 축소 연산을 다시 작성할 수 있습니다.사용자 지정 기능이 필요한 맵 리듀스 작업의 경우
$accumulator및$function집계 연산자를 사용할 수 있습니다. 이러한 연산자를 사용하여 JavaScript에서 사용자 지정 집계 표현식을 정의할 수 있습니다.
맵 리듀스 대안으로서의 집계 파이프라인 예시는 다음을 참조하세요.
정의
mapReducemapReduce명령을 사용하면 컬렉션에 대한 맵 리듀스 집계 작업을 실행할 수 있습니다.팁
mongosh에서 이 명령을mapReduce()헬퍼 메서드를 통해서도 실행할 수 있습니다.헬퍼 메서드는
mongosh사용자에게 편리하지만 데이터베이스 명령과 동일한 수준의 정보를 반환하지 못할 수 있습니다. 편의가 필요하지 않거나 추가 리턴 필드가 필요한 경우 데이터베이스 명령을 사용합니다.
호환성
이 명령은 다음 환경에서 호스팅되는 배포에서 사용할 수 있습니다.
MongoDB Atlas: 클라우드에서의 MongoDB 배포를 위한 완전 관리형 서비스
중요
이 명령은 M0, M2 및 M5 클러스터에서 지원되지 않습니다. 자세한 내용은 지원되지 않는 명령을 참조하세요.
MongoDB Enterprise: MongoDB의 구독 기반 자체 관리 버전
MongoDB Community: MongoDB의 소스 사용 가능 무료 자체 관리 버전
구문
참고
mapReduce 명령의 구문은 다음과 같습니다.
db.runCommand( { mapReduce: <string>, map: <string or JavaScript>, reduce: <string or JavaScript>, finalize: <string or JavaScript>, out: <output>, query: <document>, sort: <document>, limit: <number>, scope: <document>, jsMode: <boolean>, verbose: <boolean>, bypassDocumentValidation: <boolean>, collation: <document>, maxTimeMS: <integer>, writeConcern: <document>, comment: <any> } )
명령 필드
명령은 다음 필드를 인수로 사용합니다.
필드 | 유형 | 설명 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
문자열 | 맵 리듀스를 수행할 컬렉션의 이름입니다. 이 컬렉션은 뷰는 맵 축소 작업을 지원하지 않습니다. | |||||||||||
JavaScript 또는 문자열 |
자세한내용은 map 함수에 대한 요구 사항을 참조하세요. | |||||||||||
JavaScript 또는 문자열 | 특정 자세한 내용은 reduce 함수에 대한 요구 사항을 참조하세요. | |||||||||||
문자열 또는 문서 | ||||||||||||
문서 | 선택 사항입니다. | |||||||||||
문서 | 선택 사항입니다. 입력 문서를 정렬합니다. 이 옵션은 최적화에 유용합니다. 예를 들어 정렬 키를 방출 키와 동일하게 지정하여 축소 작업을 줄이도록 할 수 있습니다. 정렬 키는 이 컬렉션의 기존 인덱스에 있어야 합니다. | |||||||||||
숫자 | 선택 사항입니다. | |||||||||||
JavaScript 또는 문자열 | 선택 사항. 자세한 내용은 finalize 함수에 대한 요구 사항을 참조하세요. | |||||||||||
문서 | 선택 사항입니다. | |||||||||||
부울 | 선택 사항입니다. 기본값은
| |||||||||||
부울 | ||||||||||||
부울 | 선택 사항. 출력 옵션이 로 | |||||||||||
문서 | 선택 사항. 작업에 사용할 데이터 정렬을 지정합니다. 데이터 정렬을 사용하면 대소문자 및 악센트 표시 규칙과 같은 문자열 비교에 대한 언어별 규칙을 지정할 수 있습니다. 데이터 정렬 옵션의 구문은 다음과 같습니다: 데이터 정렬을 지정할 때 데이터 정렬이 지정되지 않았지만 컬렉션에 기본 데이터 정렬이 있는 경우( 컬렉션 또는 연산에 대한 데이터 정렬이 지정되지 않은 경우, MongoDB는 이전 버전에서 문자열 비교에 사용된 간단한 이진 비교를 사용합니다. 한 연산에 대해 여러 데이터 정렬을 지정할 수 없습니다. 예를 들어 필드별로 서로 다른 데이터 정렬을 지정할 수 없으며 정렬과 함께 찾기를 수행하는 경우 찾기 와 정렬에서 각각 다른 데이터 정렬을 사용하는 것은 허용되지 않습니다. 버전 3.4에 새로 추가되었습니다. | |||||||||||
| non-negative integer | 선택 사항. 시간 제한을 밀리초 단위로 지정합니다. MongoDB는 | ||||||||||
문서 | 선택 사항입니다. 컬렉션에 출력할 때 사용할 쓰기 고려를 나타내는 문서입니다. 기본 쓰기 고려를 사용하지 않으려면 생략합니다. | |||||||||||
| any | 선택 사항. 이 명령에 첨부할 사용자 제공 코멘트입니다. 설정되면 이 설명은 다음 위치에서 이 명령의 레코드와 함께 표시됩니다.
댓글은 유효한 모든 BSON types (문자열, 정수, 객체, 배열 등)이 될 수 있습니다. |
사용법
다음은 mapReduce 명령의 프로토타입 사용 예시입니다.
var mapFunction = function() { ... }; var reduceFunction = function(key, values) { ... }; db.runCommand( { mapReduce: <input-collection>, map: mapFunction, reduce: reduceFunction, out: { merge: <output-collection> }, query: <query> } )
참고
MongoDB의 자바스크립트
함수에 대한 map 요구 사항
map 함수는 각 입력 문서를 0개 이상의 문서로 변환하는 역할을 합니다. scope 매개변수에 정의된 변수에 액세스할 수 있으며 다음과 같은 프로토타입이 있습니다.
function() { ... emit(key, value); }
map 함수에는 다음과 같은 요구 사항이 있습니다.
map함수에서 현재 문서를 함수 내의this로 참조합니다.map함수는 어떤 이유로든 데이터베이스에 액세스해서는 안됩니다.map함수는 순수해야 하거나 함수 외부에 영향을 미치지 않아야 합니다(예: 부작용).map함수는 선택적으로emit(key,value)를 여러 번 호출하여key와value를 연결하는 출력 문서를 생성할 수 있습니다.
다음 map 함수는 입력 문서의 status 필드 값에 따라 emit(key,value)를 0회 또는 1회 호출합니다.
function() { if (this.status == 'A') emit(this.cust_id, 1); }
다음 map 함수는 입력 문서의 items 필드에 있는 요소 수에 따라 emit(key,value)를 여러 번 호출할 수 있습니다.
function() { this.items.forEach(function(item){ emit(item.sku, 1); }); }
함수에 대한 reduce 요구 사항
reduce 함수의 프로토타입은 다음과 같습니다.
function(key, values) { ... return result; }
reduce 함수는 다음과 같은 동작을 나타냅니다.
reduce함수는 읽기 작업을 수행하는 경우에도 데이터베이스에 액세스해서는 안됩니다.reduce함수는 외부 시스템에 영향을 주어서는 안됩니다.MongoDB는 동일한 키에 대해
reduce함수를 두 번 이상 호출할 수 있습니다. 이 경우 해당 키에 대한reduce함수의 이전 출력은 해당 키에 대한 다음reduce함수 호출에 대한 입력 값 중 하나가 됩니다.reduce함수는scope매개변수에 정의된 변수에 액세스할 수 있습니다.reduce에 대한 입력은 MongoDB의 최대 BSON 문서 크기 절반보다 크지 않아야 합니다. 큰 문서가 반환된 후 후속reduce단계에서 함께 결합되면 이 요구 사항을 위반할 수 있습니다.
동일한 키에 대해 reduce 함수를 두 번 이상 호출할 수 있으므로 다음 속성이 참이여야 합니다.
반환 객체의 유형은
map함수에서 방출한value의 유형과 동일해야 합니다.reduce함수는 연관성이 있어야 합니다. 다음 설명이 참이어야 합니다.reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] ) reduce함수는 멱등성이 있어야 합니다. 다음 설명이 참이어야 합니다.reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray ) reduce함수는 가환적이어야 합니다. 즉,valuesArray요소의 순서가reduce함수의 출력에 영향을 주지 않아야 하므로 다음 명령문이 참이어야 합니다.reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )
함수에 대한 finalize 요구 사항
finalize 함수의 프로토타입은 다음과 같습니다.
function(key, reducedValue) { ... return modifiedObject; }
finalize 함수는 인수로 reduce 함수의 key 값과 reducedValue를 받습니다. 다음 사항에 유의하세요.
finalize함수는 어떤 이유로든 데이터베이스에 액세스해서는 안됩니다.finalize함수는 순수해야 하거나 함수 외부에 영향을 미치지 않아야 합니다(예: 부작용).finalize함수는scope매개변수에 정의된 변수에 액세스할 수 있습니다.
out 옵션
out 매개변수에 대해 다음 옵션을 지정할 수 있습니다.
컬렉션으로 출력
이 옵션은 새 컬렉션으로 출력되며 복제본 세트의 세컨더리 노드에서는 사용할 수 없습니다.
out: <collectionName>
작업을 사용하여 컬렉션으로 출력
참고
버전 4.2부터 MongoDB는 다음을 더 이상 사용하지 않습니다.
새 샤드 컬렉션을 생성하는 맵 리듀스 옵션과 맵 리듀스를 위한 샤드 옵션의 사용을 더 이상 지원하지 않습니다. 샤드 컬렉션으로 출력하려면 먼저 샤드 컬렉션을 생성하세요. MongoDB 4.2 또한 기존 샤드 컬렉션의 교체를 더 이상 사용하지 않습니다.
이 옵션은 out에 이미 존재하는 컬렉션을 전달할 때만 사용할 수 있습니다. 복제본 세트의 세컨더리 노드는 이 기능을 사용할 수 없습니다.
out: { <action>: <collectionName> [, db: <dbName>] [, sharded: <boolean> ] }
작업을 사용하여 컬렉션에 출력하는 경우 out에는 다음과 같은 매개변수가 있습니다.
<action>: 다음 작업 중 하나를 지정합니다.replace<collectionName>이 있는 컬렉션이 있는 경우<collectionName>의 내용을 바꿉니다.merge출력 컬렉션이 이미 존재하는 경우 새 결과를 기존 결과와 병합합니다. 기존 문서에 새 결과와 동일한 키가 있는 경우 해당 기존 문서를 덮어씁니다.
reduce출력 컬렉션이 이미 존재하는 경우 새 결과를 기존 결과와 병합합니다. 기존 문서에 새 결과와 동일한 키가 있는 경우 새 문서와 기존 문서 모두에
reduce함수를 적용하고 결과로 기존 문서를 덮어씁니다.
db:선택 사항입니다. 맵 리듀스 작업으로 출력을 기록할 데이터베이스의 이름입니다. 기본적으로 이 데이터베이스는 입력 컬렉션과 동일한 데이터베이스가 됩니다.
인라인 출력
메모리에서 맵 리듀스 연산을 수행하고 결과를 반환합니다. 이 옵션은 복제본 세트의 세컨더리 노드에서 out에 대해 사용할 수 있는 유일한 옵션입니다.
out: { inline: 1 }
결과는 BSON 문서의 최대 크기에 맞아야 합니다.
필요한 액세스 권한
MongoDB 배포에서 인증을 시행하는 경우 mapReduce 명령을 실행하는 사용자는 다음 권한 작업을 보유해야 합니다.
{out : inline} 출력 옵션으로 맵 리듀스:
컬렉션으로 출력할 때 replace 작업을 사용하여 맵 리듀스:
컬렉션으로 출력할 때 merge 또는 reduce 작업을 사용하여 맵 리듀스:
readWrite 기본 제공 역할은 맵 리듀스 집계를 수행하는 데 필요한 권한을 제공합니다.
제한 사항
mapReduce 명령은 더 이상 afterClusterTime을 지원하지 않습니다. 따라서 mapReduce 인과적으로 일관된 세션과 연결될 수 없습니다.
맵-리듀스 예시
mongosh에서 db.collection.mapReduce() 메서드는 mapReduce 명령을 감싸는 래퍼(wrapper)입니다. 다음 예에서는 db.collection.mapReduce() 메서드를 사용합니다.
이 섹션의 예제는 사용자 지정 집계 표현식이 없는 집계 파이프라인 대안을 제시합니다.사용자 정의 표현식을 사용하는 대안에 대해서는 맵 리듀스에서 집계 파이프라인으로 변환 예제를 참조하세요.
이 문서로 샘플 컬렉션 orders을 만드세요.
db.orders.insertMany([ { _id: 1, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-01"), price: 25, items: [ { sku: "oranges", qty: 5, price: 2.5 }, { sku: "apples", qty: 5, price: 2.5 } ], status: "A" }, { _id: 2, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-08"), price: 70, items: [ { sku: "oranges", qty: 8, price: 2.5 }, { sku: "chocolates", qty: 5, price: 10 } ], status: "A" }, { _id: 3, cust_id: "Busby Bee", ord_date: new Date("2020-03-08"), price: 50, items: [ { sku: "oranges", qty: 10, price: 2.5 }, { sku: "pears", qty: 10, price: 2.5 } ], status: "A" }, { _id: 4, cust_id: "Busby Bee", ord_date: new Date("2020-03-18"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }, { _id: 5, cust_id: "Busby Bee", ord_date: new Date("2020-03-19"), price: 50, items: [ { sku: "chocolates", qty: 5, price: 10 } ], status: "A"}, { _id: 6, cust_id: "Cam Elot", ord_date: new Date("2020-03-19"), price: 35, items: [ { sku: "carrots", qty: 10, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" }, { _id: 7, cust_id: "Cam Elot", ord_date: new Date("2020-03-20"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }, { _id: 8, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 75, items: [ { sku: "chocolates", qty: 5, price: 10 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" }, { _id: 9, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 55, items: [ { sku: "carrots", qty: 5, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 }, { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }, { _id: 10, cust_id: "Don Quis", ord_date: new Date("2020-03-23"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" } ])
고객당 총 가격 반환
orders 컬렉션에서의 맵 리듀스 연산을 수행하여 cust_id별로 그룹화합니다. 그리고 각 cust_id에 대한 price의 합계를 계산하세요.
각 입력 문서를 처리할 맵 함수를 다음과 같이 정의하세요.
이 함수에서
this는 맵 리듀스 작업이 처리하고 있는 문서를 나타냅니다.이 함수는 각 문서에 대해
price을cust_id에 매핑하고cust_id및price을 출력합니다.
var mapFunction1 = function() { emit(this.cust_id, this.price); }; 두 개의 인수
keyCustId와valuesPrices을 사용하여 상응하는 리듀스 함수를 정의하세요.valuesPrices는 맵 함수에서 발생한price값들로 구성된 배열이며, 이 값들은keyCustId로 그룹화되어 있습니다.이 함수는
valuesPrice배열을 해당 요소의 합으로 리듀스합니다.
var reduceFunction1 = function(keyCustId, valuesPrices) { return Array.sum(valuesPrices); }; mapFunction1맵 함수와reduceFunction1리듀스 함수를 사용하여orders컬렉션의 모든 문서에 대해 맵-리듀스를 수행하세요.db.orders.mapReduce( mapFunction1, reduceFunction1, { out: "map_reduce_example" } ) 이 연산은
map_reduce_example이라는 컬렉션에 해당 결과를 출력합니다.map_reduce_example컬렉션이 이미 존재하는 경우 이 연산은 해당 콘텐츠를 이 맵-리듀스 작업의 결과로 바꿉니다.map_reduce_example컬렉션을 쿼리하여 결과를 확인합니다.db.map_reduce_example.find().sort( { _id: 1 } ) 이 작업은 다음 문서를 반환합니다.
{ "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Busby Bee", "value" : 125 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Don Quis", "value" : 155 }
집계 대안
사용 가능한 집계 파이프라인 연산자를 사용하면 사용자 지정 함수를 정의하지 않고도 맵-리듀스 작업을 다시 작성할 수 있습니다.
db.orders.aggregate([ { $group: { _id: "$cust_id", value: { $sum: "$price" } } }, { $out: "agg_alternative_1" } ])
$group단계는cust_id으로 그룹화하고value필드를 계산합니다 ($sum도 참조하세요).value필드에는 각cust_id의 총price가 포함되어 있습니다.이 단계에서는 다음 문서를 다음 단계로 출력합니다.
{ "_id" : "Don Quis", "value" : 155 } { "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Busby Bee", "value" : 125 } 그런 다음
$out은 결과를agg_alternative_1컬렉션에 씁니다.$out대신$merge를 사용할 수도 있습니다.agg_alternative_1컬렉션을 쿼리하여 결과를 확인합니다.db.agg_alternative_1.find().sort( { _id: 1 } ) 이 작업은 다음 문서를 반환합니다.
{ "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Busby Bee", "value" : 125 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Don Quis", "value" : 155 }
팁
사용자 정의 집계 표현식을 사용하는 대안은 맵-리듀스에서 집계 파이프라인으로 변환 예제를 참조하세요.
품목당 평균 수량을 사용하여 주문 및 총 수량 계산하기
다음 예제에서는 ord_date 값이 2020-03-01 이상인 모든 문서에 대한 orders 컬렉션에서의 대한 맵-리듀스 연산을 볼 수 있습니다.
해당 예제에서의 연산은 다음과 같습니다.
item.sku필드별로 그룹화하고 각sku에 대해 주문 수와 총 주문 수량을 계산합니다.각
sku값에 대한 주문당 평균 수량을 계산하고 결과를 출력 컬렉션에 병합합니다.
결과를 병합할 때 기존 문서에 새 결과와 동일한 키가 있으면 작업이 기존 문서를 덮어씁니다. 동일한 키를 가진 기존 문서가 없는 경우에는 해당 문서가 삽입됩니다.
예시 단계:
각 입력 문서를 처리할 맵 함수를 다음과 같이 정의하세요.
이 함수에서
this는 맵 리듀스 작업이 처리하고 있는 문서를 나타냅니다.함수는 각 항목에 대해
sku를 새로운value객체에 연결합니다. 이 객체에는count값1과 주문에 대한 항목qty가 포함되어 있으며,sku(key에 저장됨)와value를 내보냅니다.
var mapFunction2 = function() { for (var idx = 0; idx < this.items.length; idx++) { var key = this.items[idx].sku; var value = { count: 1, qty: this.items[idx].qty }; emit(key, value); } }; 두 개의 인수
keySKU와countObjVals을 사용하여 상응하는 리듀스 함수를 정의하세요.countObjVals맵 함수가 리듀서 함수에 전달한 그룹화된keySKU값에 매핑된 객체를 가지고 있는 배열입니다.이 함수는
countObjVals배열을count및qty필드를 포함하는 단일 객체reducedValue로 줄입니다.reducedVal에서count필드는 개별 배열 요소의count필드 합계를 포함하고qty필드는 개별 배열 요소의qty필드 합계를 포함합니다.
var reduceFunction2 = function(keySKU, countObjVals) { reducedVal = { count: 0, qty: 0 }; for (var idx = 0; idx < countObjVals.length; idx++) { reducedVal.count += countObjVals[idx].count; reducedVal.qty += countObjVals[idx].qty; } return reducedVal; }; 두 개의 인수
key와reducedVal을 사용하여 최종 함수를 정의합니다. 이 함수는reducedVal객체를 수정하여avg라는 계산된 필드를 추가하고 수정된 객체를 반환합니다.var finalizeFunction2 = function (key, reducedVal) { reducedVal.avg = reducedVal.qty/reducedVal.count; return reducedVal; }; mapFunction2,reduceFunction2및finalizeFunction2함수를 사용하여orders컬렉션에 대해 맵-리듀스 작업을 수행하세요.db.orders.mapReduce( mapFunction2, reduceFunction2, { out: { merge: "map_reduce_example2" }, query: { ord_date: { $gte: new Date("2020-03-01") } }, finalize: finalizeFunction2 } ); 이 작업은
query필드를 사용하여ord_date가new Date("2020-03-01")이상인 문서만 선택합니다. 그런 다음 결과를 컬렉션map_reduce_example2에 출력합니다.map_reduce_example2컬렉션이 이미 존재하는 경우 작업은 기존 콘텐츠를 이 맵-리듀스 연산의 결과와 병합합니다. 즉, 기존 문서에 새 결과와 동일한 키가 있는 경우 연산은 기존 문서를 덮어씁니다. 동일한 키를 가진 기존 문서가 없는 경우 해당 문서가 삽입됩니다.map_reduce_example2컬렉션을 쿼리하여 결과를 확인합니다.db.map_reduce_example2.find().sort( { _id: 1 } ) 이 작업은 다음 문서를 반환합니다.
{ "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } } { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } } { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } } { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } } { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } }
집계 대안
사용 가능한 집계 파이프라인 연산자를 사용하면 사용자 지정 함수를 정의하지 않고도 맵-리듀스 작업을 다시 작성할 수 있습니다.
db.orders.aggregate( [ { $match: { ord_date: { $gte: new Date("2020-03-01") } } }, { $unwind: "$items" }, { $group: { _id: "$items.sku", qty: { $sum: "$items.qty" }, orders_ids: { $addToSet: "$_id" } } }, { $project: { value: { count: { $size: "$orders_ids" }, qty: "$qty", avg: { $divide: [ "$qty", { $size: "$orders_ids" } ] } } } }, { $merge: { into: "agg_alternative_3", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } } ] )
$match단계에서는ord_date가new Date("2020-03-01")이상인 문서만 선택합니다.$unwind단계에서는items배열 필드별로 문서를 세분화하여 각 배열 요소에 대한 문서를 출력합니다. 예시:{ "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "apples", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "oranges", "qty" : 8, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "pears", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 4, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-18T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 5, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-19T00:00:00Z"), "price" : 50, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } ... $group단계는items.sku를 기준으로 그룹화하여 각 sku에 대해 다음과 같이 계산합니다.qty필드.qty필드는 다음을 포함합니다.- 각
items.sku에 대한 총qty($sum참조).
orders_ids배열.orders_ids필드는 다음을 포함합니다.items.sku에 대한 고유 주문_id배열 ($addToSet참조).
{ "_id" : "chocolates", "qty" : 15, "orders_ids" : [ 2, 5, 8 ] } { "_id" : "oranges", "qty" : 63, "orders_ids" : [ 4, 7, 3, 2, 9, 1, 10 ] } { "_id" : "carrots", "qty" : 15, "orders_ids" : [ 6, 9 ] } { "_id" : "apples", "qty" : 35, "orders_ids" : [ 9, 8, 1, 6 ] } { "_id" : "pears", "qty" : 10, "orders_ids" : [ 3 ] } $project단계에서는 맵 리듀스의 출력을 미러링하여_id와value두 필드를 갖도록 출력 문서를 재구성합니다.$project는 다음과 같이 설정합니다.$unwind단계에서는items배열 필드별로 문서를 세분화하여 각 배열 요소에 대한 문서를 출력합니다. 예시:{ "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "apples", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "oranges", "qty" : 8, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "pears", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 4, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-18T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 5, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-19T00:00:00Z"), "price" : 50, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } ... $group단계는items.sku를 기준으로 그룹화하여 각 sku에 대해 다음과 같이 계산합니다.qty필드.qty필드에는$sum을 사용하여 계산된 각items.sku별 주문된 총qty가 포함되어 있습니다.orders_ids배열.orders_ids필드는$addToSet을 사용하여 계산된items.sku의 고유한 주문_id배열을 포함하고 있습니다.
{ "_id" : "chocolates", "qty" : 15, "orders_ids" : [ 2, 5, 8 ] } { "_id" : "oranges", "qty" : 63, "orders_ids" : [ 4, 7, 3, 2, 9, 1, 10 ] } { "_id" : "carrots", "qty" : 15, "orders_ids" : [ 6, 9 ] } { "_id" : "apples", "qty" : 35, "orders_ids" : [ 9, 8, 1, 6 ] } { "_id" : "pears", "qty" : 10, "orders_ids" : [ 3 ] } $project단계에서는 맵 리듀스의 출력을 미러링하여_id와value두 필드를 갖도록 출력 문서를 재구성합니다.$project는 다음과 같이 설정합니다.$size를 사용하여value.count를orders_ids배열의 크기로 설정합니다.value.qty를 입력 문서의qty필드로 설정합니다.
{ "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } } { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } } { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } } { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } } { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } } 마지막으로
$merge는 출력을 컬렉션agg_alternative_3에 씁니다. 기존 문서에 새 결과와 동일한 키_id가 있는 경우 작업은 기존 문서를 덮어씁니다. 동일한 키를 가진 기존 문서가 없는 경우 작업이 문서를 삽입합니다.agg_alternative_3컬렉션을 쿼리하여 결과를 확인합니다.db.agg_alternative_3.find().sort( { _id: 1 } ) 이 작업은 다음 문서를 반환합니다.
{ "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } } { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } } { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } } { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } } { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } }
팁
사용자 정의 집계 표현식을 사용하는 대안은 맵-리듀스에서 집계 파이프라인으로 변환 예제를 참조하세요.
자세한 내용 및 예제는 맵 리듀스 페이지 및 증분 맵 리듀스 수행을 참조하세요.
출력
결과를 컬렉션에 쓰도록 출력 매개변수를 설정한 경우 mapReduce 명령은 다음 형식의 문서를 반환합니다.
{ "result" : "map_reduce_example", "ok" : 1 }
결과를 인라인으로 출력하도록 출력 매개변수를 설정하면 mapReduce 명령은 다음 형식의 문서를 반환합니다.
{ "results" : [ { "_id" : <key>, "value" :<reduced or finalizedValue for key> }, ... ], "ok" : <int> }
mapReduce.results인라인으로 작성된 출력의 경우 결과 문서의 배열입니다. 각 결과 문서에는 두 개의 필드가 포함됩니다.
_id필드에key값이 포함되어 있습니다,value필드에 연결된key에 대한 축소 또는 확정된 값이 포함되어 있습니다.
mapReduce.ok1값은mapReduce명령이 성공적으로 실행되었음을 나타냅니다.0값은 오류를 나타냅니다.
앞서 언급한 명령별 반환 필드 외에도 db.runCommand()에는 추가 정보가 포함되어 있습니다.
복제본 세트의 경우:
$clusterTime,operationTime.샤딩된 클러스터의 경우:
operationTime및$clusterTime.
이러한 필드에 대한 자세한 내용은 db.runCommand 응답을 참조하세요.