mapReduce
참고
맵 리듀스의 대안으로서의 집계 파이프라인
MongoDB 5.0 부터 맵 리듀스 는 더 이상 사용되지 않습니다.
맵 리듀스 대신 집계 파이프라인을 사용해야 합니다. 집계 파이프라인은 맵 리듀스보다 성능과 유용성 측면에서 더 우수합니다.
4}
$group
$merge
, 등과 같은 집계 파이프라인 단계를 사용하여 맵 축소 연산을 다시 작성할 수 있습니다.사용자 지정 기능이 필요한 맵 리듀스 작업의 경우
$accumulator
및$function
집계 연산자를 사용할 수 있습니다. 이러한 연산자를 사용하여 JavaScript에서 사용자 지정 집계 표현식을 정의할 수 있습니다.
맵 리듀스 대안으로서의 집계 파이프라인 예시는 다음을 참조하세요.
정의
mapReduce
mapReduce
명령을 사용하면 컬렉션에 대해 맵 리듀스 애그리게이션 작업을 실행할 수 있습니다.팁
mongosh
에서 이 명령을mapReduce()
헬퍼 메서드를 통해서도 실행할 수 있습니다.헬퍼 메서드는
mongosh
사용자에게 편리하지만 데이터베이스 명령과 동일한 수준의 정보를 반환하지 못할 수 있습니다. 편의가 필요하지 않거나 추가 리턴 필드가 필요한 경우 데이터베이스 명령을 사용합니다.
호환성
이 명령은 다음 환경에서 호스팅되는 배포에서 사용할 수 있습니다.
MongoDB Atlas: 클라우드에서의 MongoDB 배포를 위한 완전 관리형 서비스
중요
이 명령은 M0, M2 및 M5 클러스터에서 지원되지 않습니다. 자세한 내용은 지원되지 않는 명령을 참조하세요.
MongoDB Enterprise: MongoDB의 구독 기반 자체 관리 버전
MongoDB Community: MongoDB의 소스 사용 가능 무료 자체 관리 버전
구문
참고
명령은 다음과 같은 구문을 가집니다:
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는 이전 버전에서 문자열 비교에 사용된 간단한 이진 비교를 사용합니다. 한 연산에 대해 여러 데이터 정렬을 지정할 수 없습니다. 예를 들어 필드별로 서로 다른 데이터 정렬을 지정할 수 없으며 정렬과 함께 찾기를 수행하는 경우 찾기 와 정렬에서 각각 다른 데이터 정렬을 사용하는 것은 허용되지 않습니다. | |||||||||||
| 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.ok
1
값은mapReduce
명령이 성공적으로 실행되었음을 나타냅니다.0
값은 오류를 나타냅니다.
앞서 언급한 명령별 반환 필드 외에도 db.runCommand()
에는 추가 정보가 포함되어 있습니다.
복제본 세트의 경우:
$clusterTime
,operationTime
.샤딩된 클러스터의 경우:
operationTime
및$clusterTime
.
이러한 필드에 대한 자세한 내용은 db.runCommand 응답을 참조하세요.