문서 메뉴

문서 홈애플리케이션 개발MongoDB 매뉴얼

$merge (aggregation)

이 페이지의 내용

  • 정의
  • 호환성
  • 구문
  • 고려 사항
  • 제한 사항
  • 예제

참고

이 페이지에서는 집계 파이프라인 결과를 컬렉션으로 출력하는 $merge 단계에 대해 설명합니다. 문서를 단일 문서로 병합하는 $mergeObjects 연산자에 대해서는 $mergeObjects 를 참조하세요.

$merge

집계 파이프라인 의 결과를 지정된 컬렉션에 씁니다. $merge 연산자는 파이프라인의 마지막 단계여야 합니다.

$merge 단계:

  • 동일하거나 다른 데이터베이스의 컬렉션으로 출력할 수 있습니다.

  • 집계 중인 컬렉션과 동일한 컬렉션으로 출력할 수 있습니다. 자세한 내용 은 집계 중인 동일한 컬렉션에 출력하기를 참조하세요.

  • $merge 단계의 파이프라인은 클러스터의 모든 노드에 featureCompatibilityVersion5.0 이상으로 설정되어 있고 읽기 설정 이 세컨더리 읽기를 허용하는 경우 복제본 세트 세컨더리 노드에서 실행할 수 있습니다.

    • $merge 문의 읽기 작업은 세컨더리 노드로 전송되는 반면, 쓰기 작업은 프라이머리 노드에서만 발생합니다.

    • 모든 드라이버 버전이 복제본 세트 세컨더리 노드에 대한 $merge 작업 대상 지정을 지원하는 것은 아닙니다. 드라이버 설명서를 확인하여 드라이버가 세컨더리 노드에서 실행되는 $merge 읽기 작업에 대한 지원을 언제 추가했는지 확인합니다.

  • 출력 컬렉션이 아직 존재하지 않는 경우 새 컬렉션을 생성합니다.

  • 결과(새 문서 삽입, 문서 병합, 문서 교체, 기존 문서 유지, 작업 실패, 사용자 지정 업데이트 파이프라인으로 문서 처리)를 기존 컬렉션에 통합할 수 있습니다.

  • 샤드된 컬렉션으로 출력할 수 있습니다. 입력 컬렉션도 샤딩할 수 있습니다.

애그리게이션 결과를 컬렉션으로 출력하는 $out 단계와의 비교는 $merge$out 비교를 참조하세요.

참고

온디맨드 구체화된 보기

$merge 컬렉션을 완전히 교체하는 대신 파이프라인 결과를 기존 출력 컬렉션에 통합할 수 있습니다. 이 기능을 사용하면 파이프라인이 실행될 때 출력 컬렉션의 콘텐츠가 점진적으로 업데이트되는 온디맨드 구체화된 보기를 만들 수 있습니다.

이 사용 사례에 대한 자세한 내용은 이 페이지의 예제 및 온디맨드 구체화된 뷰를 참조하세요.

구체화된 보기는 읽기 전용 보기와 별개입니다. 읽기 전용 보기를 만드는 방법에 대한 자세한 내용은 읽기 전용 보기를 참조하십시오.

다음 환경에서 호스팅되는 배포에 $merge 사용할 수 있습니다.

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

$merge 의 구문은 다음과 같습니다:

{ $merge: {
into: <collection> -or- { db: <db>, coll: <collection> },
on: <identifier field> -or- [ <identifier field1>, ...], // Optional
let: <variables>, // Optional
whenMatched: <replace|keepExisting|merge|fail|pipeline>, // Optional
whenNotMatched: <insert|discard|fail> // Optional
} }

예를 들면 다음과 같습니다.

{ $merge: { into: "myOutput", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }

동일한 데이터베이스의 컬렉션에 쓰는 것을 포함하여 $merge 에 대한 모든 기본 옵션을 사용하는 경우 간소화된 형식을 사용할 수 있습니다.

{ $merge: <collection> } // Output collection is in the same database

$merge 는 다음 필드가 있는 문서를 사용합니다.

필드
설명
into

출력 컬렉션입니다. 다음 중 하나를 지정합니다.

  • 집계가 실행되는 동일한 데이터베이스의 컬렉션에 출력할 문자열인 컬렉션 이름입니다. 예를 들면 다음과 같습니다.

    into: "myOutput"

  • 지정된 데이터베이스의 컬렉션으로 출력할 문서의 데이터베이스 및 컬렉션 이름입니다. 예를 들면 다음과 같습니다.

    into: { db:"myDB", coll:"myOutput" }

참고

  • 출력 컬렉션이 존재하지 않으면 $merge 이 컬렉션을 생성합니다.

    • 복제본 세트 또는 독립형의 경우 출력 데이터베이스가 존재하지 않으면 $merge 가 데이터베이스도 생성합니다.

    • 샤딩된 클러스터의 경우 지정된 출력 데이터베이스가 이미 존재해야 합니다.

  • 출력 컬렉션은 샤드된 컬렉션일 수 있습니다.

선택 사항. 문서의 고유 식별자 역할을 하는 필드입니다. 식별자는 결과 문서가 출력 컬렉션의 기존 문서 와 일치 하는지 여부를 결정합니다. 다음 중 하나를 지정합니다.

  • 단일 필드 이름을 문자열로 입력합니다. 예를 들면 다음과 같습니다.

    on: "_id"

  • 배열의 필드 조합입니다. 예를 들면 다음과 같습니다.

    on: [ "date", "customerId" ]
    배열의 필드 순서는 중요하지 않으며 동일한 필드를 여러 번 지정할 수 없습니다.

지정된 필드에 대해

  • 집계 결과 문서에는 on 필드가 _id 필드가 아닌 한 on에 지정된 필드가 포함되어야 합니다. 결과 문서에서 _id 필드가 누락된 경우, MongoDB가 자동으로 추가합니다.

  • 지정한 필드에 하나 이상의 필드에 널 또는 배열 값을 포함할 수 없습니다.

에는 on $merge 식별자 필드에 해당하는 키가 있는 고유한 인덱스가 필요합니다. 인덱스 키 사양의 순서는 중요하지 않지만 고유 인덱스는 on 필드만 키로 포함해야 합니다.

  • 또한 인덱스는 집계의 데이터 정렬과 동일한 데이터 정렬을 가져야 합니다.

  • 고유 인덱스는 희소 인덱스일 수 있습니다.

  • 고유 인덱스는 부분 인덱스일 수 없습니다.

  • 이미 존재하는 출력 컬렉션의 경우 해당 인덱스가 이미 존재해야 합니다.

on 의 기본값은 출력 컬렉션에 따라 다릅니다.

  • 출력 컬렉션이 존재하지 않는 경우, on 식별자는 필드여야 하며 기본값은 _id 필드입니다. 해당 고유 _id 인덱스가 자동으로 생성됩니다.

    존재하지 않는 컬렉션에 대해 다른 on 식별자 필드를 사용하려면 먼저 원하는 필드에 고유 인덱스를 생성하여 컬렉션을 만들 수 있습니다. 예제는 존재하지 않는 출력 컬렉션 섹션을 참조하세요.

  • 기존 출력 컬렉션이 샤딩 해제된 경우 on 식별자는 기본적으로 _id 필드로 설정됩니다.

  • 기존 출력 컬렉션이 샤드 컬렉션인 경우, on 식별자는 기본적으로 모든 샤드 키 필드와 _id 필드로 설정됩니다. 다른 on 식별자를 지정하는 경우 on 에는 모든 샤드 키 필드가 포함되어야 합니다.

선택 사항.$merge 결과 문서와 컬렉션의 기존 문서가 지정된 on 필드에 대해 동일한 값을 갖는 경우 의 동작입니다.

다음 두 가지 중 하나를 지정할 수 있습니다.

  • 미리 정의된 동작 문자열 중 하나입니다.

    작업
    설명

    출력 컬렉션 의 기존 문서를 일치하는 결과 문서로 바꿉니다.

    바꾸기를 수행할 때 대체 문서로 인해 _id 값이 수정될 수 없으며 출력 컬렉션이 샤딩된 경우 샤드 키 값도 수정할 수 없습니다. 그렇지 않으면 작업이 오류를 생성합니다.

    이 오류를 방지하려면 on 필드에 _id 필드가 포함되어 있지 않은 경우 애그리게이션 결과에서 _id 필드를 제거하여 이전 $unset 단계 등에서 오류를 방지합니다.

    "merge" (기본값)

    일치하는 문서를 병합합니다($mergeObjects 연산자와 유사).

    • 결과 문서에 기존 문서에 없는 필드가 포함된 경우 이러한 새 필드를 기존 문서에 추가합니다.

    • 결과 문서에 기존 문서의 필드가 포함된 경우 기존 필드 값을 결과 문서의 값으로 바꿉니다.

    예를 들어 출력 컬렉션에 문서가 있는 경우입니다.

    { _id: 1, a: 1, b: 1 }

    그리고 집계 결과에는 문서가 있습니다.

    { _id: 1, b: 5, z: 1 }

    그러면 병합된 문서가 됩니다.

    { _id: 1, a: 1, b: 5, z: 1 }

    병합을 수행할 때 병합된 문서로 인해 _id 값이 수정될 수 없으며 출력 컬렉션이 샤딩된 경우 분할 키 값도 수정할 수 없습니다. 그렇지 않으면 작업이 오류를 생성합니다.

    이 오류를 방지하려면 on 필드에 _id 필드가 포함되어 있지 않은 경우 애그리게이션 결과에서 _id 필드를 제거하여 이전 $unset 단계 등에서 오류를 방지합니다.

    집계 작업을 중지하고 실패합니다. 이전 문서의 출력 컬렉션에 대한 변경 사항은 반환되지 않습니다.

  • 컬렉션의 문서를 업데이트하기 위한 집계 파이프라인입니다.

    [ <stage1>, <stage2> ... ]

    파이프라인은 다음 단계로만 구성될 수 있습니다.

    파이프라인은 on 필드의 값을 수정할 수 없습니다. 예를 들어 month 필드에서 일치하는 경우 파이프라인은 month 필드를 수정할 수 없습니다.

    whenMatched pipeline$<field>를 사용해 출력 컬렉션에 있는 기존 문서의 필드에 직접 액세스할 수 있습니다.

    집계 결과 문서의 필드에 액세스하려면 다음 중 하나를 사용합니다.

    • 필드에 액세스하기 위한 기본 제공 $$new 변수입니다. 구체적으로는 $$new.<field> 입니다. $$new 변수는 let 지정이 생략된 경우에만 사용할 수 있습니다.

      참고

      MongoDB 4.2.2부터 $$new 변수는 예약되어 있으며 재정의할 수 없습니다.

    • let 필드의 사용자 정의 변수입니다.

      변수 이름과 함께 이중 달러 기호 ($$) 접두사를 $$<variable_name> 형식으로 지정합니다. 예: $$year. 변수가 문서로 설정된 경우 $$<variable_name>.<field> 형식으로 문서 필드를 포함할 수도 있습니다. 예: $$year.month.

      더 많은 예제는 변수를 사용하여 병합을 사용자 지정하기를 참조하세요.

선택 사항. whenMatched 파이프라인에서 사용할 변수를 지정합니다.

변수 이름과 값 표현식이 있는 문서를 지정합니다.

{ <variable_name_1>: <expression_1>,
...,
<variable_name_n>: <expression_n> }

지정하지 않으면 기본값은 { new: "$$ROOT" } 입니다( ROOT 참조). whenMatched 파이프라인$$new 변수에 액세스할 수 있습니다.

참고

MongoDB 4.2.2부터 $$new 변수는 예약되어 있으며 재정의할 수 없습니다.

whenMatched 파이프라인의 변수에 액세스하려면 다음을 수행합니다.

변수 이름과 함께 이중 달러 기호 ($$) 접두사를 $$<variable_name> 형식으로 지정합니다. 예: $$year. 변수가 문서로 설정된 경우 $$<variable_name>.<field> 형식으로 문서 필드를 포함할 수도 있습니다. 예: $$year.month.

예제는 변수를 사용하여 병합을 사용자 지정하기를 참조하세요.

선택 사항. 결과 문서가 아웃 컬렉션의 기존 문서와 일치하지 않는 경우 $merge 의 동작입니다.

미리 정의된 동작 문자열 중 하나를 지정할 수 있습니다:

작업
설명
"insert" (기본값)

문서를 출력 컬렉션에 삽입합니다.

문서를 삭제합니다. 특히 $merge 은 문서를 출력 컬렉션에 삽입하지 않습니다.

집계 작업을 중지하고 실패합니다. 출력 컬렉션에 이미 기록된 변경 사항은 반환되지 않습니다.

집계 파이프라인 결과에서 _id 필드가 문서에 없는 경우 $merge 단계에서 자동으로 생성합니다.

예를 들어, 다음 집계 파이프라인에서 $project 은(는) $merge 으)로 전달된 문서에서 _id 필드를 제외합니다. $merge 가 이러한 문서를 "newCollection" 에 작성하면 $merge 는 새 _id 필드와 값을 생성합니다.

db.sales.aggregate( [
{ $project: { _id: 0 } },
{ $merge : { into : "newCollection" } }
] )

$merge 작업은 지정된 출력 컬렉션이 존재하지 않는 경우 새 컬렉션을 만듭니다.

  • 출력 컬렉션은 $merge 가 컬렉션에 첫 번째 문서를 쓸 때 생성되며 즉시 표시됩니다.

  • 애그리게이션이 실패하면 오류가 발생하기 전에 $merge 가 완료한 모든 쓰기는 롤백되지 않습니다.

참고

복제본 세트 또는 독립형의 경우 출력 데이터베이스가 존재하지 않으면 $merge 가 데이터베이스도 생성합니다.

샤딩된 클러스터의 경우 지정된 출력 데이터베이스가 이미 존재해야 합니다.

출력 컬렉션이 존재하지 않는 경우 $merge 에서는 on 식별자가 _id 필드여야 합니다. 존재하지 않는 컬렉션에 다른 on 필드 값을 사용하려면 먼저 원하는 필드에 고유 인덱스를 생성하여 컬렉션을 만들 수 있습니다. 예를 들어 출력 컬렉션 newDailySales201905 이(가) 존재하지 않고 salesDate 필드를 on 식별자로 지정하려는 경우입니다.

db.newDailySales201905.createIndex( { salesDate: 1 }, { unique: true } )
db.sales.aggregate( [
{ $match: { date: { $gte: new Date("2019-05-01"), $lt: new Date("2019-06-01") } } },
{ $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, totalqty: { $sum: "$quantity" } } },
{ $project: { _id: 0, salesDate: { $toDate: "$_id" }, totalqty: 1 } },
{ $merge : { into : "newDailySales201905", on: "salesDate" } }
] )

$merge 단계는 샤드 컬렉션으로 출력할 수 있습니다. 출력 컬렉션이 샤딩되면 $merge_id 필드와 모든 샤드 키 필드를 식별자의 기본값 으로 사용 합니다. 기본값을 재정의하는 경우 on 식별자에는 모든 샤드 키 필드가 포함되어야 합니다.

{ $merge: {
into: "<shardedColl>" or { db:"<sharding enabled db>", coll: "<shardedColl>" },
on: [ "<shardkeyfield1>", "<shardkeyfield2>",... ], // Shard key fields and any additional fields
let: <variables>, // Optional
whenMatched: <replace|keepExisting|merge|fail|pipeline>, // Optional
whenNotMatched: <insert|discard|fail> // Optional
} }

예를 들어, sharding enabled 있는 database에서 sh.shardCollection() 메서드를 사용하여 postcode 필드를 샤드 키로 사용하여 새 collection newrestaurants 를 생성합니다.

sh.enableSharding("exampledb"); // Sharding must be enabled in the database
sh.shardCollection(
"exampledb.newrestaurants", // Namespace of the collection to shard
{ postcode: 1 }, // Shard key
);

newrestaurants 컬렉션에는 월별 신규 레스토랑 오픈에 대한 정보(date 필드) 및 우편번호(샤드 키)가 포함된 문서가 포함됩니다. 즉, on 식별자는 ["date", "postcode"] 입니다(필드의 순서는 중요하지 않음). $merge 에는 on 식별자 필드에 해당하는 키가 있는 고유 인덱스가 필요하므로 고유 인덱스를 생성합니다(필드 순서는 중요하지 않음). [1]

use exampledb
db.newrestaurants.createIndex( { postcode: 1, date: 1 }, { unique: true } )

샤드된 컬렉션 restaurants 과 생성된 고유 인덱스를 사용하면 $merge 를 사용하여 이 컬렉션에 애그리게이션 결과를 출력할 수 있으며, 이 예에서와 같이 [ "date", "postcode" ] 에서 일치합니다.

use exampledb
db.openings.aggregate([
{ $group: {
_id: { date: { $dateToString: { format: "%Y-%m", date: "$date" } }, postcode: "$postcode" },
restaurants: { $push: "$restaurantName" } } },
{ $project: { _id: 0, postcode: "$_id.postcode", date: "$_id.date", restaurants: 1 } },
{ $merge: { into: "newrestaurants", "on": [ "date", "postcode" ], whenMatched: "replace", whenNotMatched: "insert" } }
])
[1] sh.shardCollection() 2} 메서드는 옵션을 전달할 때 샤드 { unique: true } 키가 범위 기반이고 , 컬렉션이 비어 있으며, 샤드 키의 고유 인덱스가 아직 존재하지 않는 경우 샤드 키에 고유 인덱스를 생성할 수도 있습니다. 이전 예제에서는 on 식별자가 샤드 키와 다른 필드이므로 해당 인덱스를 생성하기 위한 별도의 작업이 필요합니다.

$merge 는 집계 결과 에 온 사양에 따라 일치하는 문서가 하나 이상 포함된 경우 출력 컬렉션의 기존 문서를 대체할 수 있습니다. 따라서$merge 집계 결과에 컬렉션의 모든 기존 문서와 일치하는 문서가 포함되어 있고 whenMatched 에 'replace'를 지정하는 경우 는 기존 컬렉션의 모든 문서를 대체할 수 있습니다.

그러나 집계 결과에 관계없이 기존 컬렉션을 바꾸려면 $out 대신 사용합니다.

$merge 로 인해 기존 문서의 _id 값이 변경되면 $merge 오류가 발생합니다.

이 오류를 방지하려면 on 필드에 _id 필드가 포함되어 있지 않은 경우 애그리게이션 결과에서 _id 필드를 제거하여 이전 $unset 단계 등에서 오류를 방지합니다.

또한 샤드된 컬렉션의 경우 $merge 는 기존 문서의 샤드 키 값이 변경되는 경우에도 오류를 생성합니다.

오류가 발생하기 전에 $merge 에 의해 완료된 쓰기는 롤백되지 않습니다.

필드 에 대해 가 사용하는 고유 인덱스가 집계 도중에 삭제되면 $merge 애그리게이션이 종료된다는 보장이 없습니다. 애그리게이션이 계속되면 문서에 중복된 on 필드 값이 없다는 보장이 없습니다.

$merge 출력 컬렉션의 고유 인덱스를 위반하는 문서를 작성하려고 하면 작업에서 오류가 발생합니다. 예를 들면 다음과 같습니다.

MongoDB 4 부터 시작.2.2 $merge 단계에 대해 다음 사항이 모두 참인 경우:

  • whenMatched 의 값은 집계 파이프라인입니다.

  • whenNotMatched 의 값은 insert 이며,

  • 출력 컬렉션에 일치하는 문서가 없습니다,

$merge 는 문서를 출력 컬렉션에 바로 삽입합니다.

MongoDB 4 이전 버전.2.2 $merge 단계에 대한 이러한 조건이 충족되면 whenMatched 필드에 지정된 파이프라인이 빈 입력 문서와 함께 실행됩니다. 파이프라인의 결과 문서가 출력 컬렉션에 삽입됩니다.

$merge 도입으로 MongoDB는 집계 파이프라인의 결과를 collection에 쓰기 위해 $merge$out 두 단계를 제공합니다.

  • 동일하거나 다른 데이터베이스의 컬렉션으로 출력할 수 있습니다.

  • 동일하거나 다른 데이터베이스의 컬렉션으로 출력할 수 있습니다.

  • 출력 컬렉션이 아직 존재하지 않는 경우 새 컬렉션을 생성합니다.

  • 출력 컬렉션이 아직 존재하지 않는 경우 새 컬렉션을 생성합니다.

  • 결과(새 문서 삽입, 문서 병합, 문서 교체, 기존 문서 유지, 작업 실패, 사용자 지정 업데이트 파이프라인으로 문서 처리)를 기존 컬렉션에 통합할 수 있습니다.

  • 출력 컬렉션이 이미 있는 경우 완전히 바꿉니다.

  • 샤드된 컬렉션으로 출력할 수 있습니다. 입력 컬렉션도 샤딩할 수 있습니다.

  • 출력 대상 컬렉션은 샤딩될 수 없습니다. 그러나 입력 컬렉션은 샤딩될 수 있습니다.

  • 다음 SQL 문에 해당합니다.

    • MERGE.

    • INSERT INTO T2 SELECT FROM T1.

    • SELECT INTO T2 FROM T1.

    • 머티리얼라이즈드 뷰 생성/새로 고침.

  • 다음 SQL 문에 해당합니다.

    • INSERT INTO T2 SELECT FROM T1.

    • SELECT INTO T2 FROM T1.

경고

$merge 집계 중인 동일한 컬렉션에 출력이 발생하면 문서가 여러 번 업데이트되거나 작업이 무한 루프가 발생할 수 있습니다. 이 동작은 에서 수행한 업데이트로 인해 $merge 디스크에 저장된 문서의 물리적 위치가 변경될 때 발생합니다. 문서의 물리적 위치가 변경되면$merge 에서 문서를 완전히 새로운 문서로 간주하여 추가 업데이트를 수행할 수 있습니다. 이 동작에 대한 자세한 내용은 ' 할로윈 문제'를 참조하세요.

$merge 는 집계 중인 컬렉션과 동일한 컬렉션으로 출력할 수 있습니다. $lookup 와(과) 같이 파이프라인의 다른 단계에 나타나는 컬렉션으로 출력할 수도 있습니다.

제한 사항
설명
집계 파이프라인은 트랜잭션 내에서 를 사용할 수 $merge 없습니다.
집계 파이프라인은 $merge 를 사용하여 time series 컬렉션으로 출력할 수 없습니다.
구체화된 뷰에서 분리
뷰 정의 에는 $merge 단계를 포함할 수 없습니다. 뷰 정의에 중첩된 파이프라인이 포함된 경우(예: 뷰 정의에 $facet 단계가 포함된 경우) 이 $merge 단계 제한은 중첩된 파이프라인에도 적용됩니다.
$lookup 단계
$lookup 단계의 중첩된 파이프라인 에는 $merge 단계가 포함될 수 없습니다.
$facet 단계
$facet 단계의 중첩된 파이프라인 에는 $merge 단계가 포함될 수 없습니다.
$unionWith 단계
$unionWith 단계의 중첩된 파이프라인 에는 $merge 단계가 포함될 수 없습니다.
"linearizable" readConcern

단계는 $merge 읽기 고려 와 함께 사용할 수 "linearizable" 없습니다."linearizable" db.collection.aggregate()즉, 에 읽기 고려를 지정하면 파이프라인에 단계를 포함할 수 없습니다.$merge

출력 컬렉션이 존재하지 않으면 $merge 가 컬렉션을 생성합니다.

예를 들어, zoo 데이터베이스의 salaries 이라는 컬렉션은 직원 급여 및 부서 내역으로 채워집니다.

db.getSiblingDB("zoo").salaries.insertMany([
{ "_id" : 1, employee: "Ant", dept: "A", salary: 100000, fiscal_year: 2017 },
{ "_id" : 2, employee: "Bee", dept: "A", salary: 120000, fiscal_year: 2017 },
{ "_id" : 3, employee: "Cat", dept: "Z", salary: 115000, fiscal_year: 2017 },
{ "_id" : 4, employee: "Ant", dept: "A", salary: 115000, fiscal_year: 2018 },
{ "_id" : 5, employee: "Bee", dept: "Z", salary: 145000, fiscal_year: 2018 },
{ "_id" : 6, employee: "Cat", dept: "Z", salary: 135000, fiscal_year: 2018 },
{ "_id" : 7, employee: "Gecko", dept: "A", salary: 100000, fiscal_year: 2018 },
{ "_id" : 8, employee: "Ant", dept: "A", salary: 125000, fiscal_year: 2019 },
{ "_id" : 9, employee: "Bee", dept: "Z", salary: 160000, fiscal_year: 2019 },
{ "_id" : 10, employee: "Cat", dept: "Z", salary: 150000, fiscal_year: 2019 }
])

$group$merge 단계를 사용하여 현재 salaries 컬렉션에 있는 데이터로부터 budgets ( reporting 데이터베이스에 있음)이라는 이름의 컬렉션을 처음에 만들 수 있습니다.

참고

복제본 세트 또는 독립형 배포의 경우 출력 데이터베이스가 존재하지 않으면 $merge 이 데이터베이스도 생성합니다.

샤드 클러스터 배포의 경우, 지정된 출력 데이터베이스가 이미 존재해야 합니다.

db.getSiblingDB("zoo").salaries.aggregate( [
{ $group: { _id: { fiscal_year: "$fiscal_year", dept: "$dept" }, salaries: { $sum: "$salary" } } },
{ $merge : { into: { db: "reporting", coll: "budgets" }, on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
] )
  • 급여를 fiscal_yeardept 기준으로 그룹화하는 $group 단계.

  • $merge 단계는 이전 $group 단계의 출력을 reporting 데이터베이스의 budgets 컬렉션에 씁니다.

budgets 컬렉션의 문서를 보려면 다음과 같이 하세요:

db.getSiblingDB("reporting").budgets.find().sort( { _id: 1 } )

budgets 컬렉션에는 다음 문서가 포함되어 있습니다.

{ "_id" : { "fiscal_year" : 2017, "dept" : "A" }, "salaries" : 220000 }
{ "_id" : { "fiscal_year" : 2017, "dept" : "Z" }, "salaries" : 115000 }
{ "_id" : { "fiscal_year" : 2018, "dept" : "A" }, "salaries" : 215000 }
{ "_id" : { "fiscal_year" : 2018, "dept" : "Z" }, "salaries" : 280000 }
{ "_id" : { "fiscal_year" : 2019, "dept" : "A" }, "salaries" : 125000 }
{ "_id" : { "fiscal_year" : 2019, "dept" : "Z" }, "salaries" : 310000 }

다음도 참조하세요.

다음 예제에서는 이전 예제의 컬렉션을 사용합니다.

예제 salaries 컬렉션에는 직원 급여 및 부서 기록이 포함되어 있습니다.

{ "_id" : 1, employee: "Ant", dept: "A", salary: 100000, fiscal_year: 2017 },
{ "_id" : 2, employee: "Bee", dept: "A", salary: 120000, fiscal_year: 2017 },
{ "_id" : 3, employee: "Cat", dept: "Z", salary: 115000, fiscal_year: 2017 },
{ "_id" : 4, employee: "Ant", dept: "A", salary: 115000, fiscal_year: 2018 },
{ "_id" : 5, employee: "Bee", dept: "Z", salary: 145000, fiscal_year: 2018 },
{ "_id" : 6, employee: "Cat", dept: "Z", salary: 135000, fiscal_year: 2018 },
{ "_id" : 7, employee: "Gecko", dept: "A", salary: 100000, fiscal_year: 2018 },
{ "_id" : 8, employee: "Ant", dept: "A", salary: 125000, fiscal_year: 2019 },
{ "_id" : 9, employee: "Bee", dept: "Z", salary: 160000, fiscal_year: 2019 },
{ "_id" : 10, employee: "Cat", dept: "Z", salary: 150000, fiscal_year: 2019 }

예제 budgets 컬렉션에는 연간 누적 예산이 포함되어 있습니다.

{ "_id" : { "fiscal_year" : 2017, "dept" : "A" }, "salaries" : 220000 }
{ "_id" : { "fiscal_year" : 2017, "dept" : "Z" }, "salaries" : 115000 }
{ "_id" : { "fiscal_year" : 2018, "dept" : "A" }, "salaries" : 215000 }
{ "_id" : { "fiscal_year" : 2018, "dept" : "Z" }, "salaries" : 280000 }
{ "_id" : { "fiscal_year" : 2019, "dept" : "A" }, "salaries" : 125000 }
{ "_id" : { "fiscal_year" : 2019, "dept" : "Z" }, "salaries" : 310000 }

현재 회계연도(이 예에서는 2019 ) 동안 새 직원이 salaries 컬렉션에 추가되고 새 인원수가 다음 연도에 미리 할당됩니다.

db.getSiblingDB("zoo").salaries.insertMany([
{ "_id" : 11, employee: "Wren", dept: "Z", salary: 100000, fiscal_year: 2019 },
{ "_id" : 12, employee: "Zebra", dept: "A", salary: 150000, fiscal_year: 2019 },
{ "_id" : 13, employee: "headcount1", dept: "Z", salary: 120000, fiscal_year: 2020 },
{ "_id" : 14, employee: "headcount2", dept: "Z", salary: 120000, fiscal_year: 2020 }
])

새 급여 정보를 반영하도록 budgets 컬렉션을 업데이트하기 위해 다음 집계 파이프라인은 다음을 사용합니다.

  • $match {3} 20192} 단계로 이 보다 크거나 같은 모든 문서를 찾습니다.

  • 급여를 fiscal_yeardept 기준으로 그룹화하는 $group 단계.

  • $merge 을 입력하여 결과 집합을 budgets 컬렉션에 쓰고 문서 를 동일한 _id 값(이 예에서는 회계 연도 및 부서가 있는 문서)으로 바꿉니다. 컬렉션에 일치하는 문서가 없는 문서의 경우 $merge 가 새 문서를 삽입합니다.

db.getSiblingDB("zoo").salaries.aggregate( [
{ $match : { fiscal_year: { $gte : 2019 } } },
{ $group: { _id: { fiscal_year: "$fiscal_year", dept: "$dept" }, salaries: { $sum: "$salary" } } },
{ $merge : { into: { db: "reporting", coll: "budgets" }, on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
] )

집계가 실행된 후 budgets 컬렉션에서 문서를 봅니다.

db.getSiblingDB("reporting").budgets.find().sort( { _id: 1 } )

budgets 컬렉션은 2019 회계연도의 새 급여 데이터를 통합하고 2020 회계연도에 대한 새 문서를 추가합니다.

{ "_id" : { "fiscal_year" : 2017, "dept" : "A" }, "salaries" : 220000 }
{ "_id" : { "fiscal_year" : 2017, "dept" : "Z" }, "salaries" : 115000 }
{ "_id" : { "fiscal_year" : 2018, "dept" : "A" }, "salaries" : 215000 }
{ "_id" : { "fiscal_year" : 2018, "dept" : "Z" }, "salaries" : 280000 }
{ "_id" : { "fiscal_year" : 2019, "dept" : "A" }, "salaries" : 275000 }
{ "_id" : { "fiscal_year" : 2019, "dept" : "Z" }, "salaries" : 410000 }
{ "_id" : { "fiscal_year" : 2020, "dept" : "Z" }, "salaries" : 240000 }

다음도 참조하세요.

$merge 가 컬렉션의 기존 데이터를 덮어쓰지 않도록 하려면 whenMatchedkeepExisting 또는 fail로 설정합니다.

zoo 데이터베이스의 예제 salaries 컬렉션에는 직원 급여 및 부서 내역이 포함되어 있습니다.

{ "_id" : 1, employee: "Ant", dept: "A", salary: 100000, fiscal_year: 2017 },
{ "_id" : 2, employee: "Bee", dept: "A", salary: 120000, fiscal_year: 2017 },
{ "_id" : 3, employee: "Cat", dept: "Z", salary: 115000, fiscal_year: 2017 },
{ "_id" : 4, employee: "Ant", dept: "A", salary: 115000, fiscal_year: 2018 },
{ "_id" : 5, employee: "Bee", dept: "Z", salary: 145000, fiscal_year: 2018 },
{ "_id" : 6, employee: "Cat", dept: "Z", salary: 135000, fiscal_year: 2018 },
{ "_id" : 7, employee: "Gecko", dept: "A", salary: 100000, fiscal_year: 2018 },
{ "_id" : 8, employee: "Ant", dept: "A", salary: 125000, fiscal_year: 2019 },
{ "_id" : 9, employee: "Bee", dept: "Z", salary: 160000, fiscal_year: 2019 },
{ "_id" : 10, employee: "Cat", dept: "Z", salary: 150000, fiscal_year: 2019 }

reporting 데이터베이스의 컬렉션 orgArchive 에는 지난 회계연도의 과거 부서별 조직 기록이 포함되어 있습니다. 보관된 기록은 수정해서는 안 됩니다.

{ "_id" : ObjectId("5cd8c68261baa09e9f3622be"), "employees" : [ "Ant", "Gecko" ], "dept" : "A", "fiscal_year" : 2018 }
{ "_id" : ObjectId("5cd8c68261baa09e9f3622bf"), "employees" : [ "Ant", "Bee" ], "dept" : "A", "fiscal_year" : 2017 }
{ "_id" : ObjectId("5cd8c68261baa09e9f3622c0"), "employees" : [ "Bee", "Cat" ], "dept" : "Z", "fiscal_year" : 2018 }
{ "_id" : ObjectId("5cd8c68261baa09e9f3622c1"), "employees" : [ "Cat" ], "dept" : "Z", "fiscal_year" : 2017 }

orgArchive 0} 컬렉션은 및 필드에 고유한 복합 인덱스가 fiscal_year dept 있습니다. 특히 동일한 회계 연도 및 부서 조합에 대해 최대 하나의 레코드가 있어야 합니다.

db.getSiblingDB("reporting").orgArchive.createIndex ( { fiscal_year: 1, dept: 1 }, { unique: true } )

현재 회계연도 말(이 예에서는 2019 )에 salaries 컬렉션에 다음 문서가 포함됩니다.

{ "_id" : 1, "employee" : "Ant", "dept" : "A", "salary" : 100000, "fiscal_year" : 2017 }
{ "_id" : 2, "employee" : "Bee", "dept" : "A", "salary" : 120000, "fiscal_year" : 2017 }
{ "_id" : 3, "employee" : "Cat", "dept" : "Z", "salary" : 115000, "fiscal_year" : 2017 }
{ "_id" : 4, "employee" : "Ant", "dept" : "A", "salary" : 115000, "fiscal_year" : 2018 }
{ "_id" : 5, "employee" : "Bee", "dept" : "Z", "salary" : 145000, "fiscal_year" : 2018 }
{ "_id" : 6, "employee" : "Cat", "dept" : "Z", "salary" : 135000, "fiscal_year" : 2018 }
{ "_id" : 7, "employee" : "Gecko", "dept" : "A", "salary" : 100000, "fiscal_year" : 2018 }
{ "_id" : 8, "employee" : "Ant", "dept" : "A", "salary" : 125000, "fiscal_year" : 2019 }
{ "_id" : 9, "employee" : "Bee", "dept" : "Z", "salary" : 160000, "fiscal_year" : 2019 }
{ "_id" : 10, "employee" : "Cat", "dept" : "Z", "salary" : 150000, "fiscal_year" : 2019 }
{ "_id" : 11, "employee" : "Wren", "dept" : "Z", "salary" : 100000, "fiscal_year" : 2019 }
{ "_id" : 12, "employee" : "Zebra", "dept" : "A", "salary" : 150000, "fiscal_year" : 2019 }
{ "_id" : 13, "employee" : "headcount1", "dept" : "Z", "salary" : 120000, "fiscal_year" : 2020 }
{ "_id" : 14, "employee" : "headcount2", "dept" : "Z", "salary" : 120000, "fiscal_year" : 2020 }

방금 종료된 회계연도 2019 를 포함하도록 orgArchive 컬렉션을 업데이트하기 위해 다음 집계 파이프라인은 다음을 사용합니다.

  • $match 단계는 fiscal_year2019 인 모든 문서를 찾는 단계입니다.

  • $group 단계는 fiscal_yeardept 별로 직원을 그룹화합니다.

  • $project 단계에서 _id 필드를 표시하지 않고 별도의 deptfiscal_year 필드를 추가합니다. 문서가 $merge 로 전달되면 $merge 는 문서에 대한 새 _id 필드를 자동으로 생성합니다.

  • $merge 을 입력하여 결과 세트를 orgArchive 에 씁니다.

    $merge 단계는 deptfiscal_year 필드 있는 문서와 일치하는 경우 fails 를 일치시킵니다. 즉, 동일한 부서 및 회계 연도에 대한 문서가 이미 존재하는 경우 $merge 오류가 발생합니다.

db.getSiblingDB("zoo").salaries.aggregate( [
{ $match: { fiscal_year: 2019 }},
{ $group: { _id: { fiscal_year: "$fiscal_year", dept: "$dept" }, employees: { $push: "$employee" } } },
{ $project: { _id: 0, dept: "$_id.dept", fiscal_year: "$_id.fiscal_year", employees: 1 } },
{ $merge : { into : { db: "reporting", coll: "orgArchive" }, on: [ "dept", "fiscal_year" ], whenMatched: "fail" } }
] )

작업 후 orgArchive 컬렉션에는 다음 문서가 포함됩니다.

{ "_id" : ObjectId("5caccc6a66b22dd8a8cc419f"), "employees" : [ "Ahn", "Bess" ], "dept" : "A", "fiscal_year" : 2017 }
{ "_id" : ObjectId("5caccc6a66b22dd8a8cc419e"), "employees" : [ "Ahn", "Gee" ], "dept" : "A", "fiscal_year" : 2018 }
{ "_id" : ObjectId("5caccd0b66b22dd8a8cc438e"), "employees" : [ "Ahn", "Zeb" ], "dept" : "A", "fiscal_year" : 2019 }
{ "_id" : ObjectId("5caccc6a66b22dd8a8cc41a0"), "employees" : [ "Carl" ], "dept" : "Z", "fiscal_year" : 2017 }
{ "_id" : ObjectId("5caccc6a66b22dd8a8cc41a1"), "employees" : [ "Bess", "Carl" ], "dept" : "Z", "fiscal_year" : 2018 }
{ "_id" : ObjectId("5caccd0b66b22dd8a8cc438d"), "employees" : [ "Bess", "Carl", "Wen" ], "dept" : "Z", "fiscal_year" : 2019 }

orgArchive 컬렉션에 부서 "A" 및/또는 "B" 에 대한 2019 에 대한 문서가 이미 포함되어 있는 경우 중복 키 오류로 인해 집계가 실패합니다. 그러나 오류가 발생하기 전에 삽입된 문서는 롤백되지 않습니다.

일치하는 문서에 대해 keepExisting 을 지정하면 애그리게이션이 일치하는 문서에 영향을 주지 않고 중복 키 오류를 발생시키지 않습니다. 마찬가지로 replace 를 지정하면 작업이 실패하지 않습니다. 그러나 이 작업은 기존 문서를 대체합니다.

기본적으로 애그리게이션 결과의 문서가 컬렉션의 문서와 일치하면 $merge 단계에서 문서를 병합 합니다.

예제 컬렉션 purchaseorders 은 분기 및 지역별 구매 주문 정보로 채워집니다.

db.purchaseorders.insertMany( [
{ _id: 1, quarter: "2019Q1", region: "A", qty: 200, reportDate: new Date("2019-04-01") },
{ _id: 2, quarter: "2019Q1", region: "B", qty: 300, reportDate: new Date("2019-04-01") },
{ _id: 3, quarter: "2019Q1", region: "C", qty: 700, reportDate: new Date("2019-04-01") },
{ _id: 4, quarter: "2019Q2", region: "B", qty: 300, reportDate: new Date("2019-07-01") },
{ _id: 5, quarter: "2019Q2", region: "C", qty: 1000, reportDate: new Date("2019-07-01") },
{ _id: 6, quarter: "2019Q2", region: "A", qty: 400, reportDate: new Date("2019-07-01") },
] )

예시 collection reportedsales 는 분기 및 지역별로 보고된 판매 정보로 채워집니다.

db.reportedsales.insertMany( [
{ _id: 1, quarter: "2019Q1", region: "A", qty: 400, reportDate: new Date("2019-04-02") },
{ _id: 2, quarter: "2019Q1", region: "B", qty: 550, reportDate: new Date("2019-04-02") },
{ _id: 3, quarter: "2019Q1", region: "C", qty: 1000, reportDate: new Date("2019-04-05") },
{ _id: 4, quarter: "2019Q2", region: "B", qty: 500, reportDate: new Date("2019-07-02") },
] )

보고 목적으로 다음 형식으로 분기별로 데이터를 보려고 한다고 가정합니다.

{ "_id" : "2019Q1", "sales" : 1950, "purchased" : 1200 }
{ "_id" : "2019Q2", "sales" : 500, "purchased" : 1700 }

$merge 를 사용하여 purchaseorders 컬렉션과 reportedsales 컬렉션의 결과를 병합하여 새 컬렉션 quarterlyreport 을 만들 수 있습니다.

0} 컬렉션을 만들려면 다음 파이프라인을 사용할 수 있습니다:quarterlyreport

db.purchaseorders.aggregate( [
{ $group: { _id: "$quarter", purchased: { $sum: "$qty" } } }, // group purchase orders by quarter
{ $merge : { into: "quarterlyreport", on: "_id", whenMatched: "merge", whenNotMatched: "insert" } }
])
첫 번째 단계:

2} 단계는 $group 분기별로 그룹화하고 를 사용하여 필드를 $sumqty purchased 필드에 추가합니다. 예를 들면 다음과 같습니다.

quarterlyreport 0} 컬렉션을 만들려면 이 파이프라인을 사용할 수 있습니다:

{ "_id" : "2019Q2", "purchased" : 1700 }
{ "_id" : "2019Q1", "purchased" : 1200 }
두 번째 단계:
$merge 단계에서는 동일한 데이터베이스의 quarterlyreport 컬렉션에 문서를 씁니다. _id 필드에서 일치 하는 컬렉션의 기존 문서를 찾으면 스테이지에서 일치하는 문서를 병합합니다. 그렇지 않으면 스테이지에서 문서를 삽입합니다. 처음 생성할 때는 일치하는 문서가 없어야 합니다.

컬렉션의 문서를 보려면 다음 작업을 실행합니다.

db.quarterlyreport.find().sort( { _id: 1 } )

컬렉션에는 다음 문서가 포함되어 있습니다.

{ "_id" : "2019Q1", "sales" : 1200, "purchased" : 1200 }
{ "_id" : "2019Q2", "sales" : 1700, "purchased" : 1700 }

마찬가지로, reportedsales 컬렉션에 대해 다음 집계 파이프라인을 실행하여 판매 결과를 quarterlyreport 컬렉션에 병합합니다.

db.reportedsales.aggregate( [
{ $group: { _id: "$quarter", sales: { $sum: "$qty" } } }, // group sales by quarter
{ $merge : { into: "quarterlyreport", on: "_id", whenMatched: "merge", whenNotMatched: "insert" } }
])
첫 번째 단계:

2} 단계는 $group 분기별로 그룹화하고 를 사용하여 필드를 $sumqty sales 필드에 추가합니다. 예를 들면 다음과 같습니다.

{ "_id" : "2019Q2", "sales" : 500 }
{ "_id" : "2019Q1", "sales" : 1950 }
두 번째 단계:
$merge 단계에서는 동일한 데이터베이스의 quarterlyreport 컬렉션에 문서를 씁니다. _id 필드(분기)에서 일치 하는 컬렉션의 기존 문서를 찾으면 스테이지에서 일치하는 문서를 병합합니다. 그렇지 않으면 스테이지에서 문서를 삽입합니다.

데이터가 병합된 후 quarterlyreport 컬렉션의 문서를 보려면 다음 작업을 실행하세요.

db.quarterlyreport.find().sort( { _id: 1 } )

컬렉션에는 다음 문서가 포함되어 있습니다.

{ "_id" : "2019Q1", "sales" : 1950, "purchased" : 1200 }
{ "_id" : "2019Q2", "sales" : 500, "purchased" : 1700 }

$merge 는 문서가 일치하는 경우 사용자 지정 업데이트 파이프라인 을 사용할 수 있습니다. whenMatched 파이프라인 은 다음과 같은 단계를 가질 수 있습니다.

예제 컬렉션 votes 은 일일 투표 집계로 채워집니다. 다음 문서로 collection을 생성합니다.

db.votes.insertMany( [
{ date: new Date("2019-05-01"), "thumbsup" : 1, "thumbsdown" : 1 },
{ date: new Date("2019-05-02"), "thumbsup" : 3, "thumbsdown" : 1 },
{ date: new Date("2019-05-03"), "thumbsup" : 1, "thumbsdown" : 1 },
{ date: new Date("2019-05-04"), "thumbsup" : 2, "thumbsdown" : 2 },
{ date: new Date("2019-05-05"), "thumbsup" : 6, "thumbsdown" : 10 },
{ date: new Date("2019-05-06"), "thumbsup" : 13, "thumbsdown" : 16 }
] )

또 다른 예제 컬렉션 monthlytotals 에는 최신 월별 투표 합계가 있습니다. 다음 문서로 collection을 생성합니다.

db.monthlytotals.insertOne(
{ "_id" : "2019-05", "thumbsup" : 26, "thumbsdown" : 31 }
)

매일 하루가 끝나면 그날의 투표가 votes 컬렉션에 삽입됩니다:

db.votes.insertOne(
{ date: new Date("2019-05-07"), "thumbsup" : 14, "thumbsdown" : 10 }
)

사용자 지정 파이프라인과 함께 $merge 을(를) 사용하여 컬렉션 monthlytotals 의 기존 문서를 업데이트할 수 있습니다.

db.votes.aggregate([
{ $match: { date: { $gte: new Date("2019-05-07"), $lt: new Date("2019-05-08") } } },
{ $project: { _id: { $dateToString: { format: "%Y-%m", date: "$date" } }, thumbsup: 1, thumbsdown: 1 } },
{ $merge: {
into: "monthlytotals",
on: "_id",
whenMatched: [
{ $addFields: {
thumbsup: { $add:[ "$thumbsup", "$$new.thumbsup" ] },
thumbsdown: { $add: [ "$thumbsdown", "$$new.thumbsdown" ] }
} } ],
whenNotMatched: "insert"
} }
])
첫 번째 단계:

$match 단계에서는 특정 날짜의 투표를 찾습니다. 예를 들면 다음과 같습니다.

{ "_id" : ObjectId("5ce6097c436eb7e1203064a6"), "date" : ISODate("2019-05-07T00:00:00Z"), "thumbsup" : 14, "thumbsdown" : 10 }
두 번째 단계:

$project 단계는 _id 필드를 연도-월 문자열로 설정합니다. 예를 들면 다음과 같습니다.

{ "thumbsup" : 14, "thumbsdown" : 10, "_id" : "2019-05" }
세 번째 단계:

$merge 단계에서는 동일한 데이터베이스의 monthlytotals 컬렉션에 문서를 씁니다. 스테이지에서 컬렉션에서 _id 필드 와 일치 하는 기존 문서를 찾으면 스테이지에서는 파이프라인을 사용하여 thumbsup 표와 thumbsdown 표를 추가합니다.

  • 이 파이프라인은 결과 문서의 필드에 직접 액세스할 수 없습니다. 결과 문서의 thumbsup 필드와 thumbsdown 필드에 액세스하기 위해 파이프라인은 $$new 변수 (예: $$new.thumbsup$new.thumbsdown) 를 사용합니다.

  • 이 파이프라인은 컬렉션에 있는 기존 문서의 thumbsup 필드와 thumbsdown 필드 (예: $thumbsup$thumbsdown) 에 직접 액세스할 수 있습니다.

결과 문서가 기존 문서를 대체합니다.

병합 작업 후 monthlytotals 컬렉션의 문서를 보려면 다음 작업을 실행하세요.

db.monthlytotals.find()

컬렉션에는 다음 문서가 포함되어 있습니다.

{ "_id" : "2019-05", "thumbsup" : 40, "thumbsdown" : 41 }

$merge 단계 whenMatched 필드에서 변수를 사용할 수 있습니다. 변수를 사용하려면 먼저 변수를 정의해야 합니다.

다음 중 하나 또는 둘 모두에서 변수를 정의합니다:

whenMatched에서 변수를 사용하려면 다음을 수행합니다.

변수 이름과 함께 이중 달러 기호 ($$) 접두사를 $$<variable_name> 형식으로 지정합니다. 예: $$year. 변수가 문서로 설정된 경우 $$<variable_name>.<field> 형식으로 문서 필드를 포함할 수도 있습니다. 예: $$year.month.

아래 탭은 병합 단계, 집계 명령 또는 둘 다에서 변수가 정의될 때의 동작을 보여줍니다.

← $match (aggregation)