문서 홈 → 애플리케이션 개발 → MongoDB 매뉴얼
mapReduce
참고
맵 리듀스의 대안으로서의 집계 파이프라인
MongoDB 5.0부터 맵 리듀스는 더 이상 사용되지 않습니다.
맵 리듀스 대신 aggregation pipeline을 사용해야 합니다. aggregation pipeline은 맵 리듀스보다 성능과 유용성 측면에서 더 우수합니다.
4}
$group
$merge
, 등과 같은 집계 파이프라인 단계를 사용하여 맵 축소 연산을 다시 작성할 수 있습니다.사용자 지정 기능이 필요한 맵 리듀스 작업의 경우
$accumulator
및$function
애그리게이션 연산자를 사용할 수 있습니다. 이러한 연산자를 사용하여 JavaScript에서 사용자 지정 애그리게이션 표현식을 정의할 수 있습니다.
맵 리듀스 대안으로서의 애그리게이션 파이프라인 예시는 다음을 참조하세요.
정의
mapReduce
mapReduce
명령을 사용하면 컬렉션에 대해 맵 리듀스 애그리게이션 작업을 실행할 수 있습니다.팁
mongosh
에서 이 명령은mapReduce()
헬퍼 메서드를 통해서도 실행할 수 있습니다.헬퍼 메서드는
mongosh
사용자에게 편리하지만 데이터베이스 명령과 동일한 수준의 정보를 반환하지 않을 수 있습니다. 편의가 필요하지 않거나 추가 반환 필드가 필요한 경우 database 명령을 사용합니다.
구문
참고
명령은 다음과 같은 구문을 가집니다:
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 또는 문자열 | 특정 | |||||||||||
문자열 또는 문서 | 맵 리듀스 작업의 결과를 출력할 위치를 지정합니다. 컬렉션으로 출력하거나 결과를 인라인으로 반환할 수 있습니다. 복제본 세트의 프라이머리 노드에서는 컬렉션 또는 인라인으로 출력할 수 있지만 세컨더리 노드에서는 인라인 출력만 가능합니다. 자세한 내용은 out 옵션을 참조하세요. | |||||||||||
문서 | 선택 사항입니다. | |||||||||||
문서 | 선택 사항입니다. 입력 문서를 정렬합니다. 이 옵션은 최적화에 유용합니다. 예를 들어 정렬 키를 방출 키와 동일하게 지정하여 축소 작업을 줄이도록 할 수 있습니다. 정렬 키는 이 컬렉션의 기존 인덱스에 있어야 합니다. | |||||||||||
숫자 | 선택 사항입니다. | |||||||||||
JavaScript 또는 문자열 | 선택 사항입니다. | |||||||||||
문서 | 선택 사항입니다. | |||||||||||
부울 | 선택 사항입니다. 기본값은
| |||||||||||
부울 | ||||||||||||
부울 | ||||||||||||
문서 | 선택 사항. 작업에 사용할 데이터 정렬을 지정합니다. 데이터 정렬을 사용하면 대소문자 및 악센트 표시 규칙과 같은 문자열 비교에 대한 언어별 규칙을 지정할 수 있습니다. 데이터 정렬 옵션의 구문은 다음과 같습니다:
데이터 정렬을 지정할 때 데이터 정렬이 지정되지 않았지만 컬렉션에 기본 데이터 정렬이 있는 경우( 컬렉션 또는 연산에 대한 데이터 정렬이 지정되지 않은 경우, MongoDB는 이전 버전에서 문자열 비교에 사용된 간단한 이진 비교를 사용합니다. 한 연산에 대해 여러 데이터 정렬을 지정할 수 없습니다. 예를 들어 필드별로 서로 다른 데이터 정렬을 지정할 수 없으며 정렬과 함께 찾기를 수행하는 경우 찾기 와 정렬에서 각각 다른 데이터 정렬을 사용하는 것은 허용되지 않습니다. | |||||||||||
maxTimeMS | 음수가 아닌 정수 | 선택 사항. 시간 제한을 밀리초 단위로 지정합니다. MongoDB는 | ||||||||||
문서 | 선택 사항입니다. 컬렉션에 출력할 때 사용할 쓰기 고려를 나타내는 문서입니다. 기본 쓰기 고려를 사용하지 않으려면 생략합니다. | |||||||||||
comment | 어떤 | 선택 사항. 이 명령에 첨부할 사용자 제공 코멘트입니다. 설정되면 이 설명은 다음 위치에서 이 명령의 레코드와 함께 표시됩니다.
댓글은 유효한 모든 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> } )
참고
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
:선택 사항입니다. 맵 리듀스 작업으로 출력을 기록할 데이터베이스의 이름입니다. 기본적으로 이 데이터베이스는 입력 컬렉션과 동일한 데이터베이스가 됩니다.
sharded
:참고
버전 4.2부터
sharded
옵션 사용이 더 이상 사용되지 않습니다.선택 사항입니다.
true
이고 출력 데이터베이스에서 샤딩을 활성화한 경우 맵 리듀스 작업은_id
필드를 샤드 키로 사용하여 출력 컬렉션을 샤딩합니다.true
및collectionName
이 샤딩되지 않은 기존 컬렉션인 경우 맵 리듀스가 실패합니다.
인라인 출력
메모리에서 맵 리듀스 연산을 수행하고 결과를 반환합니다. 이 옵션은 복제본 세트의 세컨더리 노드에서 out
에 대해 사용할 수 있는 유일한 옵션입니다.
out: { inline: 1 }
결과는 BSON 문서의 최대 크기에 맞아야 합니다.
필요한 액세스 권한
MongoDB deployment에서 인증을 시행하는 경우 mapReduce
명령을 실행하는 사용자는 다음 권한 작업을 보유해야 합니다.
{out : inline}
출력 옵션으로 맵 리듀스:
컬렉션으로 출력할 때 replace
작업을 사용하여 맵 리듀스:
컬렉션으로 출력할 때 merge
또는 reduce
작업을 사용하여 맵 리듀스:
readWrite
기본 제공 역할은 맵 리듀스 애그리게이션을 수행하는 데 필요한 권한을 제공합니다.
제한 사항
MongoDB 드라이버는 인과적으로 일관적인 세션 과 관련된 작업에 afterClusterTime 을 자동으로 설정합니다. MongoDB 부터 4 2시작. , 명령은 mapReduce
더 이상 afterClusterTime 을mapReduce
지원하지 않습니다. 따라서 는 인과적으로 일관적인 세션과연결될 수 없습니다.
맵-리듀스 예제
mongosh
에서 db.collection.mapReduce()
메서드는 mapReduce
명령을 감싸는 래퍼입니다. 다음 예제에서는 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.counts
MongoDB 4.2 이전 버전에서만 사용 가능
mapReduce
명령의 다양한 카운트 통계입니다.
mapReduce.counts.input
MongoDB 4.2 이전 버전에서만 사용 가능
입력 문서 수로,
mapReduce
명령이map
함수를 호출한 횟수입니다.
mapReduce.counts.emit
MongoDB 4.2 이전 버전에서만 사용 가능
mapReduce
명령이emit
함수를 호출한 횟수입니다.
mapReduce.counts.reduce
MongoDB 4.2 이전 버전에서만 사용 가능
mapReduce
명령이reduce
함수를 호출한 횟수입니다.
mapReduce.ok
1
값은mapReduce
명령이 성공적으로 실행되었음을 나타냅니다.0
값은 오류를 나타냅니다.
앞서 언급한 명령별 반환 필드 외에도 db.runCommand()
에는 추가 정보가 포함되어 있습니다.
복제본 세트의 경우:
$clusterTime
,operationTime
.클러스터의 경우:
operationTime
및$clusterTime
.
이러한 필드에 대한 자세한 내용은 db.runCommand 응답을 참조하세요.