db.collection.mapReduce()
참고
맵 리듀스의 대안으로서의 집계 파이프라인
MongoDB 5.0 부터 맵 리듀스 는 더 이상 사용되지 않습니다.
맵 리듀스 대신 집계 파이프라인을 사용해야 합니다. 집계 파이프라인은 맵 리듀스보다 성능과 유용성 측면에서 더 우수합니다.
4}
$group
$merge
, 등과 같은 집계 파이프라인 단계를 사용하여 맵 축소 연산을 다시 작성할 수 있습니다.사용자 지정 기능이 필요한 맵 리듀스 작업의 경우
$accumulator
및$function
집계 연산자를 사용할 수 있습니다. 이러한 연산자를 사용하여 JavaScript에서 사용자 지정 집계 표현식을 정의할 수 있습니다.
맵 리듀스 대안으로서의 집계 파이프라인 예시는 다음을 참조하세요.
db.collection.mapReduce(map,reduce, { <options> })
중요
Mongo쉬 방법
이 페이지에서는
mongosh
메서드에 대해 설명합니다. 이는 데이터베이스 명령 또는 Node.js와 같은 언어별 드라이버에 대한 설명서가 아닙니다.데이터베이스 명령에 대해서는
mapReduce
명령을 참조하십시오.MongoDB API 드라이버의 경우 언어별 MongoDB 드라이버 설명서를 참조하세요.
참고
뷰는 맵 축소 작업을 지원하지 않습니다.
호환성
이 메서드는 다음 환경에서 호스팅되는 배포에서 사용할 수 있습니다.
MongoDB Atlas: 클라우드에서의 MongoDB 배포를 위한 완전 관리형 서비스
중요
이 명령은 M0, M2 및 M5 클러스터에서 지원되지 않습니다. 자세한 내용은 지원되지 않는 명령을 참조하세요.
MongoDB Enterprise: MongoDB의 구독 기반 자체 관리 버전
MongoDB Community: MongoDB의 소스 사용 가능 무료 자체 관리 버전
구문
참고
db.collection.mapReduce()
의 구문은 다음과 같습니다:
db.collection.mapReduce( <map>, <reduce>, { out: <collection>, query: <document>, sort: <document>, limit: <number>, finalize: <function>, scope: <document>, jsMode: <boolean>, verbose: <boolean>, bypassDocumentValidation: <boolean> } )
db.collection.mapReduce()
다음 매개변수를 사용합니다.
Parameter | 유형 | 설명 |
---|---|---|
| JavaScript 또는 문자열 |
자세한 내용은 지도 함수에 대한 요구 사항을 참조하세요. |
| JavaScript 또는 문자열 | 특정 자세한 내용은 reduce 함수에 대한 요구 사항을 참조하세요. |
| 문서 |
|
다음 표에서는 db.collection.mapReduce()
가 수락할 수 있는 추가 인수에 대해 설명합니다.
필드 | 유형 | 설명 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
| 문자열 또는 문서 | |||||||||||
| 문서 |
| ||||||||||
| 문서 | 입력 문서를 정렬합니다. 이 옵션은 최적화에 유용합니다. 예를 들어 정렬 키를 내보내기 키와 동일하게 지정하여 축소 작업을 줄이도록 할 수 있습니다. 정렬 키는 이 컬렉션의 기존 인덱스에 있어야 합니다. | ||||||||||
| 숫자 |
| ||||||||||
| JavaScript 또는 문자열 | 선택 사항. 자세한 내용은 finalize 함수에 대한 요구 사항을 참조하세요. | ||||||||||
| 문서 |
| ||||||||||
| 부울 |
기본값은
| ||||||||||
| 부울 | 결과 정보에 기본값은 이 옵션은 무시됩니다. 결과 정보에는 항상 | ||||||||||
| 문서 | 선택 사항. 작업에 사용할 데이터 정렬을 지정합니다. 데이터 정렬을 사용하면 대소문자 및 악센트 표시 규칙과 같은 문자열 비교에 대한 언어별 규칙을 지정할 수 있습니다. 데이터 정렬 옵션의 구문은 다음과 같습니다:
데이터 정렬을 지정할 때 데이터 정렬이 지정되지 않았지만 컬렉션에 기본 데이터 정렬이 있는 경우( 컬렉션 또는 연산에 대한 데이터 정렬이 지정되지 않은 경우, MongoDB는 이전 버전에서 문자열 비교에 사용된 간단한 이진 비교를 사용합니다. 한 연산에 대해 여러 데이터 정렬을 지정할 수 없습니다. 예를 들어 필드별로 서로 다른 데이터 정렬을 지정할 수 없으며 정렬과 함께 찾기를 수행하는 경우 찾기 와 정렬에서 각각 다른 데이터 정렬을 사용하는 것은 허용되지 않습니다. 버전 3.4에 새로 추가되었습니다. | ||||||||||
| 부울 | 선택 사항. 버전 3.2에 새로 추가되었습니다. |
참고
map-reduce operations
및 $where
연산자 표현식은 mongosh
에서 사용할 수 있는 db
와 같은 특정 글로벌 함수 또는 속성에 액세스할 수 없습니다.
$where
및 연산자 map-reduce operations
표현식에 다음 JavaScript 함수 및 속성을 사용할 수 있습니다.
사용 가능한 속성 | 사용 가능한 기능 | |
---|---|---|
args MaxKey MinKey | assert() BinData() DBPointer() DBRef() doassert() emit() gc() HexData() hex_md5() isNumber() isObject() ISODate() isString() | Map() MD5() NumberInt() NumberLong() ObjectId() print() printjson() printjsononeline() sleep() Timestamp() tojson() tojsononeline() tojsonObject() UUID() version() |
함수에 대한 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 ] )
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 문서의 최대 크기에 맞아야 합니다.
함수에 대한 finalize
요구 사항
finalize
함수의 프로토타입은 다음과 같습니다.
function(key, reducedValue) { ... return modifiedObject; }
finalize
함수는 인수로 reduce
함수의 key
값과 reducedValue
를 받습니다. 다음 사항에 유의하세요.
finalize
함수는 어떤 이유로든 데이터베이스에 액세스해서는 안됩니다.finalize
함수는 순수해야 하거나 함수 외부에 영향을 미치지 않아야 합니다(예: 부작용).finalize
함수는scope
매개변수에 정의된 변수에 액세스할 수 있습니다.
맵-리듀스 예시
이 섹션의 예제는 사용자 지정 집계 표현식이 없는 집계 파이프라인 대안을 제시합니다.사용자 정의 표현식을 사용하는 대안에 대해서는 맵 리듀스에서 집계 파이프라인으로 변환 예제를 참조하세요.
이 문서로 샘플 컬렉션 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 } }
출력
db.collection.mapReduce()
메서드의 출력은 mapReduce
명령의 출력과 동일합니다. 출력에 대한 자세한 내용은 mapReduce
명령의 출력 db.collection.mapReduce()
섹션을 참조하세요.
제한 사항
db.collection.mapReduce()
는 더 이상 afterClusterTime을 지원하지 않습니다. 따라서 db.collection.mapReduce()
는 인과적으로 일관된 세션과 연결될 수 없습니다.