Docs Menu
Docs Home
/
MongoDB 매뉴얼
/ / /

mapReduce

이 페이지의 내용

  • 정의
  • 호환성
  • 구문
  • 명령 필드
  • 사용법
  • 필요한 액세스 권한
  • 제한 사항
  • 맵-리듀스 예시
  • 출력
  • 추가 정보

참고

맵 리듀스의 대안으로서의 집계 파이프라인

MongoDB 5.0 부터 맵 리듀스 는 더 이상 사용되지 않습니다.

맵 리듀스 대안으로서의 집계 파이프라인 예시는 다음을 참조하세요.

mapReduce

mapReduce 명령을 사용하면 컬렉션에 대해 맵 리듀스 애그리게이션 작업을 실행할 수 있습니다.

mongosh에서 이 명령을 mapReduce() 헬퍼 메서드를 통해서도 실행할 수 있습니다.

헬퍼 메서드는 mongosh 사용자에게 편리하지만 데이터베이스 명령과 동일한 수준의 정보를 반환하지 못할 수 있습니다. 편의가 필요하지 않거나 추가 리턴 필드가 필요한 경우 데이터베이스 명령을 사용합니다.

이 명령은 다음 환경에서 호스팅되는 배포에서 사용할 수 있습니다.

  • MongoDB Atlas: 클라우드에서의 MongoDB 배포를 위한 완전 관리형 서비스

중요

이 명령은 M0, M2 및 M5 클러스터에서 지원되지 않습니다. 자세한 내용은 지원되지 않는 명령을 참조하세요.

참고

MongoDB는 자세한 정보 표시 옵션을 무시합니다.

버전 4.2부터 MongoDB는 다음을 더 이상 사용하지 않습니다.

  • 새 샤드 컬렉션을 생성하는 맵 리듀스 옵션과 맵 리듀스를 위한 샤드 옵션의 사용을 더 이상 지원하지 않습니다. 샤드 컬렉션으로 출력하려면 먼저 샤드 컬렉션을 생성하세요. MongoDB 4.2 또한 기존 샤드 컬렉션의 교체를 더 이상 사용하지 않습니다.

명령은 다음과 같은 구문을 가집니다:

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>
}
)

명령은 다음 필드를 인수로 사용합니다.

필드
유형
설명

문자열

맵 리듀스를 수행할 컬렉션의 이름입니다. 이 컬렉션은 map 함수로 처리되기 전에 query를 사용하여 필터링됩니다.

뷰는 맵 축소 작업을 지원하지 않습니다.

JavaScript 또는 문자열

valuekey에 연결하거나 '매핑'하고 key 및 값 pair를 방출하는 JavaScript 함수입니다. 함수를 BSON types JavaScript(BSON type 13) 또는 문자열(BSON Type 2)로 지정할 수 있습니다.

자세한내용은 map 함수에 대한 요구 사항을 참조하세요.

JavaScript 또는 문자열

특정 key와 연관된 모든 values를 단일 객체로 '줄이는' JavaScript 함수입니다. 함수를 BSON types JavaScript(BSON Type 13) 또는 문자열(BSON Type 2)로 지정할 수 있습니다.

자세한 내용은 reduce 함수에 대한 요구 사항을 참조하세요.

문자열 또는 문서

맵 리듀스 작업의 결과를 출력할 위치를 지정합니다. 컬렉션으로 출력하거나 결과를 인라인으로 반환할 수 있습니다. 복제본 세트의 프라이머리 노드에서는 컬렉션 또는 인라인으로 출력할 수 있지만 세컨더리 노드에서는 인라인 출력만 가능합니다.

자세한 내용은 out 옵션을 참조하세요.

문서

선택 사항입니다. map 함수에 입력된 문서를 결정하기 위해 쿼리 연산자를 사용하여 선택 기준을 지정합니다.

문서

선택 사항입니다. 입력 문서를 정렬합니다. 이 옵션은 최적화에 유용합니다. 예를 들어 정렬 키를 방출 키와 동일하게 지정하여 축소 작업을 줄이도록 할 수 있습니다. 정렬 키는 이 컬렉션의 기존 인덱스에 있어야 합니다.

숫자

선택 사항입니다. map 함수에 입력할 수 있는 최대 문서 수를 지정합니다.

JavaScript 또는 문자열

선택 사항입니다. reduce 함수 이후의 출력을 수정하는 JavaScript 함수입니다. 함수를 BSON types JavaScript(BSON Type 13) 또는 문자열(BSON Type 2)로 지정할 수 있습니다.

자세한 내용은 finalize 함수에 대한 요구 사항을 참조하세요.

문서

선택 사항입니다. map, reducefinalize 함수에서 액세스할 수 있는 글로벌 변수를 지정합니다.

부울

선택 사항입니다. map 함수와 reduce 함수 실행 사이에 중간 데이터를 BSON 형식으로 변환할지 여부를 지정합니다.

기본값은 false입니다.

false인 경우:

  • 내부적으로 MongoDB는 map 함수에서 내보낸 JavaScript 객체를 BSON 객체로 변환합니다. 그러면 이러한 BSON 객체는 reduce 함수를 호출할 때 JavaScript 객체로 다시 변환됩니다.

  • 맵 리듀스 작업은 중간 BSON 객체를 임시 디스크 상의 저장소에 배치합니다. 이를 통해 맵 리듀스 작업을 임의로 큰 데이터 세트에 대해 실행할 수 있습니다.

true인 경우:

  • 내부적으로 map 함수 중에 방출된 JavaScript 객체는 JavaScript 객체로 남아 있습니다. reduce 함수에 대한 객체를 변환할 필요가 없으므로 실행 속도가 빨라질 수 있습니다.

  • 매퍼의 emit() 함수에 대한 고유 key 인수가 500,000개 미만인 결과 세트에만 jsMode를 사용할 수 있습니다.

부울

선택 사항입니다. 결과 정보에 timing 정보를 포함할지 여부를 지정합니다. timing 정보를 포함하려면 verbosetrue로 설정합니다.

기본값은 false입니다.

이 옵션은 무시됩니다. 결과 정보에는 항상 timing 정보가 제외됩니다. 또는 explain 모드에서 mapReduce 명령으로 를 실행 하여 타이밍 정보를 볼 수 "executionStats" "allPlansExecution" verbosity 있습니다.

부울

선택 사항. mapReduce가 작업 중에 문서 유효성 검사를 우회할 수 있도록 합니다. 이를 통해 유효성 검사 요구 사항을 충족하지 않는 문서를 삽입할 수 있습니다.

출력 옵션이 로 설정하다 inline 되어 있으면 문서 유효성 검사 가 수행되지 않습니다. 출력이 컬렉션 으로 이동하는 경우 는mapReduce 컬렉션 에 있는 유효성 검사 규칙을 관찰하고 매개 bypassDocumentValidation 변수가 true로 설정하다 되지 않는 한 유효하지 않은 문서를 삽입하지 않습니다.

문서

선택 사항.

작업에 사용할 데이터 정렬을 지정합니다.

데이터 정렬을 사용하면 대소문자 및 악센트 표시 규칙과 같은 문자열 비교에 대한 언어별 규칙을 지정할 수 있습니다.

데이터 정렬 옵션의 구문은 다음과 같습니다:

collation: {
locale: <string>,
caseLevel: <boolean>,
caseFirst: <string>,
strength: <int>,
numericOrdering: <boolean>,
alternate: <string>,
maxVariable: <string>,
backwards: <boolean>
}

데이터 정렬을 지정할 때 locale 필드는 필수이고, 다른 데이터 정렬 필드는 모두 선택 사항입니다. 필드에 대한 설명은 데이터 정렬 문서를 참조하세요.

데이터 정렬이 지정되지 않았지만 컬렉션에 기본 데이터 정렬이 있는 경우( db.createCollection() 참조), 작업은 컬렉션에 지정된 데이터 정렬을 사용합니다.

컬렉션 또는 연산에 대한 데이터 정렬이 지정되지 않은 경우, MongoDB는 이전 버전에서 문자열 비교에 사용된 간단한 이진 비교를 사용합니다.

한 연산에 대해 여러 데이터 정렬을 지정할 수 없습니다. 예를 들어 필드별로 서로 다른 데이터 정렬을 지정할 수 없으며 정렬과 함께 찾기를 수행하는 경우 찾기 와 정렬에서 각각 다른 데이터 정렬을 사용하는 것은 허용되지 않습니다.

maxTimeMS

non-negative integer

선택 사항.

시간 제한을 밀리초 단위로 지정합니다. maxTimeMS에 값을 지정하지 않으면 작업이 시간 초과되지 않습니다. 0 값은 바인딩되지 않는 기본 동작을 명시적으로 지정합니다.

MongoDB는 db.killOp()와 동일한 메커니즘을 사용하여 할당된 시간 제한을 초과하는 작업을 종료합니다. MongoDB는 지정된 중단 지점 중 하나에서만 작업을 종료합니다.

문서

선택 사항입니다. 컬렉션에 출력할 때 사용할 쓰기 고려를 나타내는 문서입니다. 기본 쓰기 고려를 사용하지 않으려면 생략합니다.

comment

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의 자바스크립트

mapReduce는 JavaScript를 사용하지만, MongoDB와의 대부분의 상호 작용은 JavaScript를 사용하지 않고 상호 작용하는 애플리케이션의 언어로 된 관용적 드라이버 를 사용합니다.

map 함수는 각 입력 문서를 0개 이상의 문서로 변환하는 역할을 합니다. scope 매개변수에 정의된 변수에 액세스할 수 있으며 다음과 같은 프로토타입이 있습니다.

function() {
...
emit(key, value);
}

map 함수에는 다음과 같은 요구 사항이 있습니다.

  • map 함수에서 현재 문서를 함수 내의 this로 참조합니다.

  • map 함수는 어떤 이유로든 데이터베이스에 액세스해서는 안됩니다.

  • map 함수는 순수해야 하거나 함수 외부에 영향을 미치지 않아야 합니다(예: 부작용).

  • map 함수는 선택적으로 emit(key,value)를 여러 번 호출하여 keyvalue를 연결하는 출력 문서를 생성할 수 있습니다.

다음 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 함수의 프로토타입은 다음과 같습니다.

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 함수의 프로토타입은 다음과 같습니다.

function(key, reducedValue) {
...
return modifiedObject;
}

finalize 함수는 인수로 reduce 함수의 key 값과 reducedValue를 받습니다. 다음 사항에 유의하세요.

  • finalize 함수는 어떤 이유로든 데이터베이스에 액세스해서는 안됩니다.

  • finalize 함수는 순수해야 하거나 함수 외부에 영향을 미치지 않아야 합니다(예: 부작용).

  • finalize 함수는 scope 매개변수에 정의된 변수에 액세스할 수 있습니다.

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의 합계를 계산하세요.

  1. 각 입력 문서를 처리할 맵 함수를 다음과 같이 정의하세요.

    • 이 함수에서 this는 맵 리듀스 작업이 처리하고 있는 문서를 나타냅니다.

    • 이 함수는 각 문서에 대해 pricecust_id에 매핑하고 cust_idprice을 출력합니다.

    var mapFunction1 = function() {
    emit(this.cust_id, this.price);
    };
  2. 두 개의 인수 keyCustIdvaluesPrices을 사용하여 상응하는 리듀스 함수를 정의하세요.

    • valuesPrices는 맵 함수에서 발생한 price 값들로 구성된 배열이며, 이 값들은 keyCustId로 그룹화되어 있습니다.

    • 이 함수는 valuesPrice 배열을 해당 요소의 합으로 리듀스합니다.

    var reduceFunction1 = function(keyCustId, valuesPrices) {
    return Array.sum(valuesPrices);
    };
  3. mapFunction1 맵 함수와 reduceFunction1 리듀스 함수를 사용하여 orders 컬렉션의 모든 문서에 대해 맵-리듀스를 수행하세요.

    db.orders.mapReduce(
    mapFunction1,
    reduceFunction1,
    { out: "map_reduce_example" }
    )

    이 연산은 map_reduce_example이라는 컬렉션에 해당 결과를 출력합니다. map_reduce_example 컬렉션이 이미 존재하는 경우 이 연산은 해당 콘텐츠를 이 맵-리듀스 작업의 결과로 바꿉니다.

  4. 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" }
])
  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 }
  2. 그런 다음 $out은 결과를 agg_alternative_1 컬렉션에 씁니다. $out 대신 $merge를 사용할 수도 있습니다.

  3. 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 컬렉션에서의 대한 맵-리듀스 연산을 볼 수 있습니다.

해당 예제에서의 연산은 다음과 같습니다.

  1. item.sku 필드별로 그룹화하고 각 sku에 대해 주문 수와 총 주문 수량을 계산합니다.

  2. sku 값에 대한 주문당 평균 수량을 계산하고 결과를 출력 컬렉션에 병합합니다.

결과를 병합할 때 기존 문서에 새 결과와 동일한 키가 있으면 작업이 기존 문서를 덮어씁니다. 동일한 키를 가진 기존 문서가 없는 경우에는 해당 문서가 삽입됩니다.

예시 단계:

  1. 각 입력 문서를 처리할 맵 함수를 다음과 같이 정의하세요.

    • 이 함수에서 this는 맵 리듀스 작업이 처리하고 있는 문서를 나타냅니다.

    • 함수는 각 항목에 대해 sku를 새로운 value 객체에 연결합니다. 이 객체에는 count1과 주문에 대한 항목 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);
    }
    };
  2. 두 개의 인수 keySKUcountObjVals을 사용하여 상응하는 리듀스 함수를 정의하세요.

    • countObjVals 맵 함수가 리듀서 함수에 전달한 그룹화된 keySKU 값에 매핑된 객체를 가지고 있는 배열입니다.

    • 이 함수는 countObjVals 배열을 countqty 필드를 포함하는 단일 객체 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;
    };
  3. 두 개의 인수 keyreducedVal을 사용하여 최종 함수를 정의합니다. 이 함수는 reducedVal 객체를 수정하여 avg라는 계산된 필드를 추가하고 수정된 객체를 반환합니다.

    var finalizeFunction2 = function (key, reducedVal) {
    reducedVal.avg = reducedVal.qty/reducedVal.count;
    return reducedVal;
    };
  4. mapFunction2, reduceFunction2finalizeFunction2 함수를 사용하여 orders 컬렉션에 대해 맵-리듀스 작업을 수행하세요.

    db.orders.mapReduce(
    mapFunction2,
    reduceFunction2,
    {
    out: { merge: "map_reduce_example2" },
    query: { ord_date: { $gte: new Date("2020-03-01") } },
    finalize: finalizeFunction2
    }
    );

    이 작업은 query 필드를 사용하여 ord_datenew Date("2020-03-01") 이상인 문서만 선택합니다. 그런 다음 결과를 컬렉션 map_reduce_example2에 출력합니다.

    map_reduce_example2 컬렉션이 이미 존재하는 경우 작업은 기존 콘텐츠를 이 맵-리듀스 연산의 결과와 병합합니다. 즉, 기존 문서에 새 결과와 동일한 키가 있는 경우 연산은 기존 문서를 덮어씁니다. 동일한 키를 가진 기존 문서가 없는 경우 해당 문서가 삽입됩니다.

  5. 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" } }
] )
  1. $match 단계에서는 ord_datenew Date("2020-03-01") 이상인 문서만 선택합니다.

  2. $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" }
    ...
  3. $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 ] }
  4. $project 단계에서는 맵 리듀스의 출력을 미러링하여 _idvalue 두 필드를 갖도록 출력 문서를 재구성합니다. $project는 다음과 같이 설정합니다.

  5. $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" }
    ...
  6. $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 ] }
  7. $project 단계에서는 맵 리듀스의 출력을 미러링하여 _idvalue 두 필드를 갖도록 출력 문서를 재구성합니다. $project는 다음과 같이 설정합니다.

    • $size 를 사용하여 value.countorders_ids 배열의 크기로 설정합니다.

    • value.qty를 입력 문서의 qty 필드로 설정합니다.

    • $divide$size를 사용하여 value.avg를 주문당 평균 주문 수량으로 설정합니다.

    { "_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 } }
  8. 마지막으로 $merge는 출력을 컬렉션 agg_alternative_3에 씁니다. 기존 문서에 새 결과와 동일한 키 _id가 있는 경우 작업은 기존 문서를 덮어씁니다. 동일한 키를 가진 기존 문서가 없는 경우 작업이 문서를 삽입합니다.

  9. 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.result

컬렉션으로 전송되는 출력의 경우 이 값은 다음 중 하나입니다.

  • 출력이 데이터베이스 이름을 지정하지 않은 경우 컬렉션 이름에 대한 문자열, 또는

  • 출력이 데이터베이스와 컬렉션 이름을 모두 지정한 경우 dbcollection 필드가 모두 있는 문서입니다.

mapReduce.results

인라인으로 작성된 출력의 경우 결과 문서의 배열입니다. 각 결과 문서에는 두 개의 필드가 포함됩니다.

  • _id 필드에 key 값이 포함되어 있습니다,

  • value 필드에 연결된 key에 대한 축소 또는 확정된 값이 포함되어 있습니다.

mapReduce.ok

1 값은 mapReduce 명령이 성공적으로 실행되었음을 나타냅니다. 0 값은 오류를 나타냅니다.

앞서 언급한 명령별 반환 필드 외에도 db.runCommand()에는 추가 정보가 포함되어 있습니다.

  • 복제본 세트의 경우: $clusterTime, operationTime.

  • 샤딩된 클러스터의 경우: operationTime$clusterTime.

이러한 필드에 대한 자세한 내용은 db.runCommand 응답을 참조하세요.

돌아가기

별개