문서 메뉴

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

$lookup (aggregation)

이 페이지의 내용

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

버전 5.0에서 변경됨

동일한 데이터베이스의 샤딩되지 않은 컬렉션에 왼쪽 외부 조인을 수행하여 "조인된" 컬렉션의 문서를 필터링하여 처리합니다. $lookup 단계는 각 입력 문서에 '조인된' 컬렉션에서 일치하는 문서를 요소로 하는 새 배열 필드를 추가합니다. $lookup 단계에서는 이러한 재구성된 문서를 다음 단계로 전달합니다.

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

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

$lookup 단계에는 다음과 같은 구문이 있습니다.

입력 문서의 필드와 "joined" 컬렉션의 문서 필드 간에 동등성 매치를 수행하기 위해 $lookup 단계에는 다음 구문이 있습니다.

{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}

$lookup 는 이러한 필드가 있는 문서를 가져옵니다.

필드
설명
FROM

조인을 수행할 동일한 데이터베이스의 컬렉션을 지정합니다. from 컬렉션을 샤딩할 수 없습니다. 자세한 내용은 샤드 컬렉션 제한을 참조하세요.

문서 입력에서 $lookup 단계까지의 필드를 지정합니다. $lookupfrom 컬렉션의 문서에서 foreignField 에 대한 localField 동등성 매치를 수행합니다. 입력 문서에 localField 이 포함되어 있지 않으면 $lookup 는 매칭을 위해 필드의 값이 null 인 것으로 처리합니다.

from 컬렉션의 문서에서 필드를 지정합니다. $lookup 는 입력 문서의 foreignField 에서 localField 에 대해 동등성 매치를 수행합니다. from 컬렉션의 문서에 foreignField 가 포함되어 있지 않은 경우 $lookup 는 매칭을 위해 값을 null 로 처리합니다.

입력 문서에 추가할 새 배열 필드의 이름을 지정합니다. 새 배열 필드에는 from 컬렉션에서 매칭되는 문서가 포함됩니다. 지정된 이름이 입력 문서에 이미 존재하는 경우 기존 필드를 덮어씁니다.

이 작업은 다음과 같은 유사 SQL 문장에 해당합니다.

SELECT *, (
SELECT ARRAY_AGG(*)
FROM <collection to join>
WHERE <foreignField> = <collection.localField>
) AS <output array field>
FROM collection;

참고

이 페이지의 SQL 문은 MongoDB 집계 파이프라인 구문과 비교할 수 있도록 포함되어 있습니다. SQL 문을 실행할 수 없습니다.

MongoDB 예시는 이 페이지를 참조하세요.

MongoDB는 다음을 지원합니다.

  • 조인된 컬렉션에서 파이프라인 실행하기.

  • 여러 조인 조건.

  • 상관관계가 있는 하위 쿼리와 상관관계가 없는 하위 쿼리.

MongoDB에서 상관 하위 쿼리는 조인된 컬렉션의 문서 필드를 참조하는 단계의 파이프라인 $lookup 입니다. 상관 관계가 없는 하위 쿼리는 조인된 필드를 참조하지 않습니다.

참고

MongoDB 부터 5 시작.0 단계, 연산자 $sampleRate 또는 $sample 연산자를 포함하는 파이프라인 단계에서 $lookup $rand 상관관계가 없는 하위 쿼리의 경우, 반복되면 항상 하위 쿼리가 다시 실행됩니다. 이전에는 하위 쿼리 출력 크기에 따라 하위 쿼리 출력이 캐시되거나 하위 쿼리가 다시 실행되었습니다.

MongoDB 상관 서브쿼리는 내부 쿼리가 외부 쿼리 값을 참조하는 SQL 상관 서브쿼리와 유사합니다. SQL 비연관 서브쿼리는 외부 쿼리 값을 참조하지 않습니다.

MongoDB 5.0 은(는) 상관관계가 있는 간결한 하위 쿼리도 지원합니다.

두 컬렉션에 대해 상관관계가 있는 하위 쿼리와 상관관계가 없는 하위 쿼리를 수행하고 단일 동등성 매치 이외의 다른 조인 조건을 수행하려면 이 $lookup 구문을 사용합니다.

{
$lookup:
{
from: <joined collection>,
let: { <var_1>: <expression>, …, <var_n>: <expression> },
pipeline: [ <pipeline to run on joined collection> ],
as: <output array field>
}
}

$lookup 단계에서는 이러한 필드가 있는 문서를 허용합니다.

필드
설명

조인 작업을 수행할 동일한 데이터베이스의 컬렉션을 지정합니다. 조인된 컬렉션은 샤딩할 수 없습니다( 샤드 컬렉션 제한 참조).

선택 사항. 파이프라인 단계에서 사용할 변수를 지정합니다. 변수 표현식을 사용하여 pipeline 에 입력되는 조인된 컬렉션 문서의 필드에 액세스합니다.

참고

파이프라인 단계에서 변수를 참조하려면 "$$<variable>" 구문을 사용합니다.

let 변수는 에 중첩된 추가 단계를 $lookup 포함하여 파이프라인 의 단계에서 액세스할 수 pipeline 있습니다.

  • $match 단계에서는 $expr 연산자를 사용하여 변수에 액세스해야 합니다. $expr 연산자를 사용하면 $match 구문 내에서 집계 표현식을 사용할 수 있습니다.

    연산자에 배치된 $eq $lt, $lte, $gt, 및 $gte 비교 $expr 연산자는 단계에서 참조된 컬렉션의 인덱스를 사용할 수 from $lookup 있습니다. 제한 사항:

    • 다중 키 인덱스 는 사용되지 않습니다.

    • 피연산자가 배열이거나 피연산자 유형이 정의되지 않은 비교에는 인덱스가 사용되지 않습니다.

    • 둘 이상의 필드 경로 피연산자와의 비교에는 인덱스가 사용되지 않습니다.

  • 파이프라인 의 다른( 이$match 아님) 단계에서는 $expr 변수에 액세스하기 위해 연산자가 필요하지 않습니다.

조인된 컬렉션에서 실행할 pipeline을 지정합니다. pipeline은 조인된 컬렉션의 결과 문서를 결정합니다. 모든 문서를 반환하려면 빈 pipeline []을 지정합니다.

pipeline 에는 $out 단계 또는 $merge 단계를 포함할 수 없습니다.

pipeline 은 조인된 문서 필드에 직접 액세스할 수 없습니다. 대신 let 옵션을 사용하여 조인된 문서 필드에 대한 변수를 정의한 다음 pipeline 단계에서 변수를 참조합니다.

참고

파이프라인 단계에서 변수를 참조하려면 "$$<variable>" 구문을 사용합니다.

let 변수는 에 중첩된 추가 단계를 $lookup 포함하여 파이프라인 의 단계에서 액세스할 수 pipeline 있습니다.

  • $match 단계에서는 $expr 연산자를 사용하여 변수에 액세스해야 합니다. $expr 연산자를 사용하면 $match 구문 내에서 집계 표현식을 사용할 수 있습니다.

    연산자에 배치된 $eq $lt, $lte, $gt, 및 $gte 비교 $expr 연산자는 단계에서 참조된 컬렉션의 인덱스를 사용할 수 from $lookup 있습니다. 제한 사항:

    • 다중 키 인덱스 는 사용되지 않습니다.

    • 피연산자가 배열이거나 피연산자 유형이 정의되지 않은 비교에는 인덱스가 사용되지 않습니다.

    • 둘 이상의 필드 경로 피연산자와의 비교에는 인덱스가 사용되지 않습니다.

  • 파이프라인 의 다른( 이$match 아님) 단계에서는 $expr 변수에 액세스하기 위해 연산자가 필요하지 않습니다.

조인된 문서에 추가할 새 배열 필드의 이름을 지정합니다. 새 배열 필드에는 조인된 컬렉션에서 일치하는 문서가 포함됩니다. 지정한 이름이 조인된 문서에 이미 존재하는 경우 기존 필드를 덮어씁니다.

이 작업은 다음과 같은 유사 SQL 문장에 해당합니다.

SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (
SELECT <documents as determined from the pipeline>
FROM <collection to join>
WHERE <pipeline>
);

다음 예시를 참조하세요.

버전 5.0에 추가.

MongoDB 5.0부터는 상관관계가 있는 하위 쿼리에 간결한 구문을 사용할 수 있습니다. 연결된 하위 쿼리는 조인된 "외부" 컬렉션 aggregate() 메서드가 실행된 "로컬" 컬렉션의 문서 필드를 참조합니다.

다음과 같은 새롭고 간결한 구문은 $expr 연산자 내부의 외부 및 로컬 필드에 대한 동등성 매치 요구 사항을 제거합니다.

{
$lookup:
{
from: <foreign collection>,
localField: <field from local collection's documents>,
foreignField: <field from foreign collection's documents>,
let: { <var_1>: <expression>, …, <var_n>: <expression> },
pipeline: [ <pipeline to run> ],
as: <output array field>
}
}

$lookup 는 이러한 필드가 있는 문서를 수락합니다.

필드
설명

로컬 컬렉션에 조인할 동일한 데이터베이스의 외부 컬렉션을 지정합니다. 외부 컬렉션은 샤딩할 수 없습니다( 샤드 컬렉션 제한 참조).

외부 문서의 foreignField와 동등성 매치를 수행하도록 로컬 문서의 localField를 지정합니다.

로컬 문서에 localField 값이 포함되어 있지 않으면 $lookup 는 일치를 위해 null 값을 사용합니다.

로컬 문서의 localField와 동등성 매치를 수행하도록 외부 문서의 foreignField를 지정합니다.

외부 문서에 foreignField 값이 포함되어 있지 않으면 $lookup 는 일치를 위해 null 값을 사용합니다.

선택 사항. 파이프라인 단계에서 사용할 변수를 지정합니다. 변수 표현식을 사용하여 pipeline 에 입력되는 문서 필드에 액세스합니다.

참고

파이프라인 단계에서 변수를 참조하려면 "$$<variable>" 구문을 사용합니다.

let 변수는 에 중첩된 추가 단계를 $lookup 포함하여 파이프라인 의 단계에서 액세스할 수 pipeline 있습니다.

  • $match 단계에서는 $expr 연산자를 사용하여 변수에 액세스해야 합니다. $expr 연산자를 사용하면 $match 구문 내에서 집계 표현식을 사용할 수 있습니다.

    연산자에 배치된 $eq $lt, $lte, $gt, 및 $gte 비교 $expr 연산자는 단계에서 참조된 컬렉션의 인덱스를 사용할 수 from $lookup 있습니다. 제한 사항:

    • 다중 키 인덱스 는 사용되지 않습니다.

    • 피연산자가 배열이거나 피연산자 유형이 정의되지 않은 비교에는 인덱스가 사용되지 않습니다.

    • 둘 이상의 필드 경로 피연산자와의 비교에는 인덱스가 사용되지 않습니다.

  • 파이프라인 의 다른( 이$match 아님) 단계에서는 $expr 변수에 액세스하기 위해 연산자가 필요하지 않습니다.

외부 컬렉션에서 실행할 pipeline을 지정합니다. pipeline은 외부 컬렉션에서 문서를 반환합니다. 모든 문서를 반환하려면 빈 pipeline []을 지정합니다.

pipeline 에는 $out 또는 $merge 단계를 포함할 수 없습니다.

pipeline 은(는) 문서 필드에 직접 액세스할 수 없습니다. 대신 let 옵션을 사용하여 문서 필드에 대한 변수를 정의한 다음 pipeline 단계에서 변수를 참조합니다.

참고

파이프라인 단계에서 변수를 참조하려면 "$$<variable>" 구문을 사용합니다.

let 변수는 에 중첩된 추가 단계를 $lookup 포함하여 파이프라인 의 단계에서 액세스할 수 pipeline 있습니다.

  • $match 단계에서는 $expr 연산자를 사용하여 변수에 액세스해야 합니다. $expr 연산자를 사용하면 $match 구문 내에서 집계 표현식을 사용할 수 있습니다.

    연산자에 배치된 $eq $lt, $lte, $gt, 및 $gte 비교 $expr 연산자는 단계에서 참조된 컬렉션의 인덱스를 사용할 수 from $lookup 있습니다. 제한 사항:

    • 다중 키 인덱스 는 사용되지 않습니다.

    • 피연산자가 배열이거나 피연산자 유형이 정의되지 않은 비교에는 인덱스가 사용되지 않습니다.

    • 둘 이상의 필드 경로 피연산자와의 비교에는 인덱스가 사용되지 않습니다.

  • 파이프라인 의 다른( 이$match 아님) 단계에서는 $expr 변수에 액세스하기 위해 연산자가 필요하지 않습니다.

외부 문서에 추가할 새 배열 필드의 이름을 지정합니다. 새 배열 필드에는 외부 컬렉션에서 일치하는 문서가 포함됩니다. 지정한 이름이 외부 문서에 이미 존재하는 경우 기존 필드를 덮어씁니다.

이 작업은 다음과 같은 유사 SQL 문장에 해당합니다.

SELECT *, <output array field>
FROM localCollection
WHERE <output array field> IN (
SELECT <documents as determined from the pipeline>
FROM <foreignCollection>
WHERE <foreignCollection.foreignField> = <localCollection.localField>
AND <pipeline match condition>
);

이 예시를 참조하세요.

$lookup 또는 $graphLookup 와 같이 여러 뷰를 포함하는 애그리게이션을 수행하는 경우 뷰의 데이터 정렬이 동일해야 합니다.

  • 버전 4 에서 변경되었습니다.2:$out $merge 단계에 또는 단계를 $lookup 포함할 수 없습니다. 즉,조인된 collection에 대한 파이프라인을 지정할 때 필드에 어느 단계도 포함할 수 pipeline 없습니다.

    {
    $lookup:
    {
    from: <collection to join>,
    let: { <var_1>: <expression>, …, <var_n>: <expression> },
    pipeline: [ <pipeline to execute on the joined collection> ], // Cannot include $out or $merge
    as: <output array field>
    }
    }

$lookup 단계에서는 from 컬렉션을 샤딩 할 수 없습니다. 그러나 aggregate() 메서드를 실행하는 컬렉션은 샤딩할 수 있습니다. 이 예에서는 구체적으로 다음과 같습니다.

db.collection.aggregate([
{ $lookup: { from: "fromCollection", ... } }
])
  • collection 는 샤딩할 수 있습니다.

  • fromCollection 은(는) 샤딩할 수 없습니다.

샤드 컬렉션을 비샤드 컬렉션과 조인하려면 샤드 컬렉션에서 집계를 실행하고 비샤드 컬렉션을 조회합니다. 예를 들면 다음과 같습니다.

db.shardedCollection.aggregate([
{ $lookup: { from: "unshardedCollection", ... } }
])

또는 여러 샤드 collection을 조인하려면 다음을 고려하세요.

  • $lookup 애그리게이션 단계를 사용하는 대신 수동 조회를 수행하도록 클라이언트 애플리케이션을 수정합니다.

  • 가능하면 collection을 조인할 필요가 없는 Realm 데이터 모델 을 사용합니다.

  • 가능하면 Atlas Data Lake $lookup 파이프라인 단계를 사용하여 샤드 컬렉션을 조회합니다.

$lookup 성능은 수행되는 작업 유형에 따라 달라집니다. 다양한 $lookup 작업에 대한 성능 고려 사항은 다음 표를 참조하세요.

$lookup 작업
성능 고려 사항
  • $lookup 연산은 단일 조인으로 동등성 매치를 수행하고, 외부 컬렉션에 foreignField에 대한 인덱스가 포함된 경우 성능이 더 우수합니다.

    중요

    foreignField에 대한 지원 인덱스가 없는 경우 단일 조인으로 동등성 매치를 수행하는 $lookup 연산의 성능이 저하될 가능성이 있습니다.

  • $lookup 연산은 관련 없는 하위 쿼리를 포함하며, 내부 파이프라인이 외부 컬렉션의 인덱스를 참조할 수 있을 때 성능이 더 우수합니다.

  • MongoDB는 소스 컬렉션과 외부 컬렉션 사이에 관계가 없기 때문에 쿼리를 캐싱하기 전에 $lookup 하위 쿼리를 한 번만 실행하면 됩니다. 하위 쿼리는 소스 컬렉션의 값을 기반으로 하지 않습니다. 이 동작은 $lookup 작업의 후속 실행에 대한 성능을 향상시킵니다.

  • $lookup 연산은 연관된 하위 쿼리를 포함하며, 다음의 조건이 적용될 때 성능이 더 우수합니다.

    • 외부 컬렉션에 foreignField에 대한 인덱스가 포함.

    • 외부 컬렉션에는 내부 파이프라인을 참조하는 인덱스가 포함.

  • 파이프라인이 많은 수의 문서를 $lookup 쿼리에 전달하는 경우 다음 전략을 사용하면 성능이 향상될 수 있습니다.

    • MongoDB가 $lookup 쿼리에 전달하는 문서 수를 줄입니다. 예를 들어 $match 단계에서 더 엄격한 필터를 설정합니다.

    • $lookup 하위 쿼리의 내부 파이프라인을 별도의 쿼리로 실행하고 $out 을(를) 사용하여 임시 컬렉션을 만듭니다. 그런 다음 단일 조인으로 동등성 매치를 실행합니다.

    • 데이터의 스키마를 재검토하여 사용 사례에 적합한지 확인합니다.

일반적인 성능 전략은 인덱싱 전략쿼리 최적화를 참조하세요.

중요

쿼리 내에서 $lookup을 과도하게 사용하면 성능이 저하될 수 있습니다. 여러 $lookup 단계를 피하려면 쿼리 성능을 최적화하는 임베디드 데이터 모델을 고려하세요.

이 문서로 orders 컬렉션을 만듭니다.

db.orders.insertMany( [
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 },
{ "_id" : 3 }
] )

이 문서로 다른 컬렉션 inventory를 만듭니다.

db.inventory.insertMany( [
{ "_id" : 1, "sku" : "almonds", "description": "product 1", "instock" : 120 },
{ "_id" : 2, "sku" : "bread", "description": "product 2", "instock" : 80 },
{ "_id" : 3, "sku" : "cashews", "description": "product 3", "instock" : 60 },
{ "_id" : 4, "sku" : "pecans", "description": "product 4", "instock" : 70 },
{ "_id" : 5, "sku": null, "description": "Incomplete" },
{ "_id" : 6 }
] )

orders 컬렉션에 대한 다음 집계 작업은 orders 컬렉션의 item 필드와 inventory 컬렉션의 sku 필드를 사용하여 orders 문서를 inventory 컬렉션의 문서와 결합합니다.

db.orders.aggregate( [
{
$lookup:
{
from: "inventory",
localField: "item",
foreignField: "sku",
as: "inventory_docs"
}
}
] )

이 작업은 다음 문서를 반환합니다.

{
"_id" : 1,
"item" : "almonds",
"price" : 12,
"quantity" : 2,
"inventory_docs" : [
{ "_id" : 1, "sku" : "almonds", "description" : "product 1", "instock" : 120 }
]
}
{
"_id" : 2,
"item" : "pecans",
"price" : 20,
"quantity" : 1,
"inventory_docs" : [
{ "_id" : 4, "sku" : "pecans", "description" : "product 4", "instock" : 70 }
]
}
{
"_id" : 3,
"inventory_docs" : [
{ "_id" : 5, "sku" : null, "description" : "Incomplete" },
{ "_id" : 6 }
]
}

이 작업은 다음과 같은 유사 SQL 문장에 해당합니다.

SELECT *, inventory_docs
FROM orders
WHERE inventory_docs IN (
SELECT *
FROM inventory
WHERE sku = orders.item
);

자세한 내용은 동등성 매치 성능 고려 사항을 참조하세요.

localField가 배열인 경우 $unwind 단계 없이 스칼라 foreignField에 일치시킬 수 있습니다.

예를 들어 다음 문서를 사용하여 예시 컬렉션 classes를 만듭니다.

db.classes.insertMany( [
{ _id: 1, title: "Reading is ...", enrollmentlist: [ "giraffe2", "pandabear", "artie" ], days: ["M", "W", "F"] },
{ _id: 2, title: "But Writing ...", enrollmentlist: [ "giraffe1", "artie" ], days: ["T", "F"] }
] )

이 문서로 다른 컬렉션 members를 만듭니다.

db.members.insertMany( [
{ _id: 1, name: "artie", joined: new Date("2016-05-01"), status: "A" },
{ _id: 2, name: "giraffe", joined: new Date("2017-05-01"), status: "D" },
{ _id: 3, name: "giraffe1", joined: new Date("2017-10-01"), status: "A" },
{ _id: 4, name: "panda", joined: new Date("2018-10-11"), status: "A" },
{ _id: 5, name: "pandabear", joined: new Date("2018-12-01"), status: "A" },
{ _id: 6, name: "giraffe2", joined: new Date("2018-12-01"), status: "D" }
] )

다음 집계 작업은 classes 컬렉션의 문서를 members 컬렉션과 결합하여 enrollmentlist 필드를 name 필드와 일치시킵니다.

db.classes.aggregate( [
{
$lookup:
{
from: "members",
localField: "enrollmentlist",
foreignField: "name",
as: "enrollee_info"
}
}
] )

이 연산은 다음을 반환합니다:

{
"_id" : 1,
"title" : "Reading is ...",
"enrollmentlist" : [ "giraffe2", "pandabear", "artie" ],
"days" : [ "M", "W", "F" ],
"enrollee_info" : [
{ "_id" : 1, "name" : "artie", "joined" : ISODate("2016-05-01T00:00:00Z"), "status" : "A" },
{ "_id" : 5, "name" : "pandabear", "joined" : ISODate("2018-12-01T00:00:00Z"), "status" : "A" },
{ "_id" : 6, "name" : "giraffe2", "joined" : ISODate("2018-12-01T00:00:00Z"), "status" : "D" }
]
}
{
"_id" : 2,
"title" : "But Writing ...",
"enrollmentlist" : [ "giraffe1", "artie" ],
"days" : [ "T", "F" ],
"enrollee_info" : [
{ "_id" : 1, "name" : "artie", "joined" : ISODate("2016-05-01T00:00:00Z"), "status" : "A" },
{ "_id" : 3, "name" : "giraffe1", "joined" : ISODate("2017-10-01T00:00:00Z"), "status" : "A" }
]
}

$mergeObjects 연산자는 여러 문서를 단일 문서로 결합합니다.

이 문서로 orders 컬렉션을 만듭니다.

db.orders.insertMany( [
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 }
] )

이 문서로 다른 컬렉션 items를 만듭니다.

db.items.insertMany( [
{ "_id" : 1, "item" : "almonds", description: "almond clusters", "instock" : 120 },
{ "_id" : 2, "item" : "bread", description: "raisin and nut bread", "instock" : 80 },
{ "_id" : 3, "item" : "pecans", description: "candied pecans", "instock" : 60 }
] )

다음 작업은 먼저 $lookup 단계를 사용하여 item 필드를 기준으로 두 컬렉션을 조인한 다음 $replaceRoot 에서$mergeObjects를 사용하여 itemsorders 에서 조인된 문서를 병합합니다.

db.orders.aggregate( [
{
$lookup: {
from: "items",
localField: "item", // field in the orders collection
foreignField: "item", // field in the items collection
as: "fromItems"
}
},
{
$replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$fromItems", 0 ] }, "$$ROOT" ] } }
},
{ $project: { fromItems: 0 } }
] )

이 작업은 다음 문서를 반환합니다.

{
_id: 1,
item: 'almonds',
description: 'almond clusters',
instock: 120,
price: 12,
quantity: 2
},
{
_id: 2,
item: 'pecans',
description: 'candied pecans',
instock: 60,
price: 20,
quantity: 1
}

파이프라인은 조인된 컬렉션에서 실행할 수 있으며 여러 조인 조건을 포함할 수 있습니다.

조인 조건은 aggregate() 메서드가 실행된 로컬 컬렉션의 필드를 참조하고 조인된 컬렉션의 필드를 참조할 수 있습니다. 이렇게 하면 두 컬렉션 간에 상호 연관된 하위 쿼리가 가능합니다.

MongoDB 5.0 은(는) 상관관계가 있는 간결한 하위 쿼리를 지원합니다.

이 문서로 orders 컬렉션을 만듭니다.

db.orders.insertMany( [
{ "_id" : 1, "item" : "almonds", "price" : 12, "ordered" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "ordered" : 1 },
{ "_id" : 3, "item" : "cookies", "price" : 10, "ordered" : 60 }
] )

이 문서로 다른 컬렉션 warehouses를 만듭니다.

db.warehouses.insertMany( [
{ "_id" : 1, "stock_item" : "almonds", warehouse: "A", "instock" : 120 },
{ "_id" : 2, "stock_item" : "pecans", warehouse: "A", "instock" : 80 },
{ "_id" : 3, "stock_item" : "almonds", warehouse: "B", "instock" : 60 },
{ "_id" : 4, "stock_item" : "cookies", warehouse: "B", "instock" : 40 },
{ "_id" : 5, "stock_item" : "cookies", warehouse: "A", "instock" : 80 }
] )

다음 예제입니다.

  • orders.itemwarehouse.stock_item 필드에 대한 조인과 함께 상관된 하위 쿼리를 사용합니다.

  • 재고가 있는 품목의 수량이 주문한 수량을 충족할 수 있는지 확인합니다.

db.orders.aggregate( [
{
$lookup:
{
from: "warehouses",
let: { order_item: "$item", order_qty: "$ordered" },
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$stock_item", "$$order_item" ] },
{ $gte: [ "$instock", "$$order_qty" ] }
]
}
}
},
{ $project: { stock_item: 0, _id: 0 } }
],
as: "stockdata"
}
}
] )

이 작업은 다음 문서를 반환합니다.

{
_id: 1,
item: 'almonds',
price: 12,
ordered: 2,
stockdata: [
{ warehouse: 'A', instock: 120 },
{ warehouse: 'B', instock: 60 }
]
},
{
_id: 2,
item: 'pecans',
price: 20,
ordered: 1,
stockdata: [ { warehouse: 'A', instock: 80 } ]
},
{
_id: 3,
item: 'cookies',
price: 10,
ordered: 60,
stockdata: [ { warehouse: 'A', instock: 80 } ]
}

이 작업은 다음과 같은 유사 SQL 문장에 해당합니다.

SELECT *, stockdata
FROM orders
WHERE stockdata IN (
SELECT warehouse, instock
FROM warehouses
WHERE stock_item = orders.item
AND instock >= orders.ordered
);

연산자에 배치된 $eq $lt, $lte, $gt, 및 $gte 비교 $expr 연산자는 단계에서 참조된 컬렉션의 인덱스를 사용할 수 from $lookup 있습니다. 제한 사항:

  • 다중 키 인덱스 는 사용되지 않습니다.

  • 피연산자가 배열이거나 피연산자 유형이 정의되지 않은 비교에는 인덱스가 사용되지 않습니다.

  • 둘 이상의 필드 경로 피연산자와의 비교에는 인덱스가 사용되지 않습니다.

예를 들어 warehouses 컬렉션에 인덱스 { stock_item: 1, instock: 1 }가 존재하는 경우입니다.

  • warehouses.stock_item 필드의 동등성 매치는 인덱스를 사용합니다.

  • warehouses.instock 필드에 대한 쿼리의 범위 부분도 복합 인덱스의 인덱스 필드를 사용합니다.

다음도 참조하세요.

집계 파이프라인 $lookup 단계는 조인된 컬렉션에서 파이프라인을 실행하여 상관관계가 없는 하위 쿼리를 허용할 수 있습니다. 상관되지 않은 하위 쿼리는 결합된 문서 필드를 참조하지 않습니다.

참고

MongoDB 부터 5 시작.0 단계, 연산자 $sampleRate 또는 $sample 연산자를 포함하는 파이프라인 단계에서 $lookup $rand 상관관계가 없는 하위 쿼리의 경우, 반복되면 항상 하위 쿼리가 다시 실행됩니다. 이전에는 하위 쿼리 출력 크기에 따라 하위 쿼리 출력이 캐시되거나 하위 쿼리가 다시 실행되었습니다.

이 문서로 absences 컬렉션을 만듭니다.

db.absences.insertMany( [
{ "_id" : 1, "student" : "Ann Aardvark", sickdays: [ new Date ("2018-05-01"),new Date ("2018-08-23") ] },
{ "_id" : 2, "student" : "Zoe Zebra", sickdays: [ new Date ("2018-02-01"),new Date ("2018-05-23") ] },
] )

이 문서로 다른 컬렉션 holidays를 만듭니다.

db.holidays.insertMany( [
{ "_id" : 1, year: 2018, name: "New Years", date: new Date("2018-01-01") },
{ "_id" : 2, year: 2018, name: "Pi Day", date: new Date("2018-03-14") },
{ "_id" : 3, year: 2018, name: "Ice Cream Day", date: new Date("2018-07-15") },
{ "_id" : 4, year: 2017, name: "New Years", date: new Date("2017-01-01") },
{ "_id" : 5, year: 2017, name: "Ice Cream Day", date: new Date("2017-07-16") }
] )

다음 작업은 holidays 컬렉션의 2018년 공휴일 정보와 함께 absences 컬렉션을 조인합니다.

db.absences.aggregate( [
{
$lookup:
{
from: "holidays",
pipeline: [
{ $match: { year: 2018 } },
{ $project: { _id: 0, date: { name: "$name", date: "$date" } } },
{ $replaceRoot: { newRoot: "$date" } }
],
as: "holidays"
}
}
] )

이 연산은 다음을 반환합니다:

{
_id: 1,
student: 'Ann Aardvark',
sickdays: [
ISODate("2018-05-01T00:00:00.000Z"),
ISODate("2018-08-23T00:00:00.000Z")
],
holidays: [
{ name: 'New Years', date: ISODate("2018-01-01T00:00:00.000Z") },
{ name: 'Pi Day', date: ISODate("2018-03-14T00:00:00.000Z") },
{ name: 'Ice Cream Day', date: ISODate("2018-07-15T00:00:00.000Z")
}
]
},
{
_id: 2,
student: 'Zoe Zebra',
sickdays: [
ISODate("2018-02-01T00:00:00.000Z"),
ISODate("2018-05-23T00:00:00.000Z")
],
holidays: [
{ name: 'New Years', date: ISODate("2018-01-01T00:00:00.000Z") },
{ name: 'Pi Day', date: ISODate("2018-03-14T00:00:00.000Z") },
{ name: 'Ice Cream Day', date: ISODate("2018-07-15T00:00:00.000Z")
}
]
}

이 작업은 다음과 같은 유사 SQL 문장에 해당합니다.

SELECT *, holidays
FROM absences
WHERE holidays IN (
SELECT name, date
FROM holidays
WHERE year = 2018
);

자세한 내용은 상관관계가 없는 하위 쿼리 성능 고려 사항을 참조하세요.

버전 5.0에 추가.

MongoDB 부터 5 시작.0, 집계 파이프라인 단계는 컬렉션 $lookup 간의 조인을 개선하는 간결한 상관관계 하위 쿼리 구문 을 지원합니다. 새로운 간결한 구문은 단계에서 연산자 내부의 외래 및 로컬 $expr $match 필드에 대한 동등성 매치 요구 사항을 제거합니다.

컬렉션 restaurants을 만듭니다:

db.restaurants.insertMany( [
{
_id: 1,
name: "American Steak House",
food: [ "filet", "sirloin" ],
beverages: [ "beer", "wine" ]
},
{
_id: 2,
name: "Honest John Pizza",
food: [ "cheese pizza", "pepperoni pizza" ],
beverages: [ "soda" ]
}
] )

음식 및 음료 주문(선택 사항)이 포함된 다른 컬렉션 orders를 만듭니다.

db.orders.insertMany( [
{
_id: 1,
item: "filet",
restaurant_name: "American Steak House"
},
{
_id: 2,
item: "cheese pizza",
restaurant_name: "Honest John Pizza",
drink: "lemonade"
},
{
_id: 3,
item: "cheese pizza",
restaurant_name: "Honest John Pizza",
drink: "soda"
}
] )

다음 예제입니다.

  • orders.restaurant_name localFieldrestaurants.name foreignField 와 일치시켜 ordersrestaurants 컬렉션을 조인합니다. pipeline 이(가) 실행되기 전에 매치가 수행됩니다.

  • 각각 $$orders_drink$beverages를 사용하여 액세스하는 orders.drinkrestaurants.beverages 필드 간에 $in 배열 일치를 수행합니다.

db.orders.aggregate( [
{
$lookup: {
from: "restaurants",
localField: "restaurant_name",
foreignField: "name",
let: { orders_drink: "$drink" },
pipeline: [ {
$match: {
$expr: { $in: [ "$$orders_drink", "$beverages" ] }
}
} ],
as: "matches"
}
}
] )

orders.drinkrestaurants.beverages 필드에 soda 값과 일치하는 항목이 있습니다. 이 출력은 matches 배열을 표시하고 일치 항목에 대해 restaurants 컬렉션의 조인된 모든 필드를 포함합니다.

{
"_id" : 1, "item" : "filet",
"restaurant_name" : "American Steak House",
"matches" : [ ]
}
{
"_id" : 2, "item" : "cheese pizza",
"restaurant_name" : "Honest John Pizza",
"drink" : "lemonade",
"matches" : [ ]
}
{
"_id" : 3, "item" : "cheese pizza",
"restaurant_name" : "Honest John Pizza",
"drink" : "soda",
"matches" : [ {
"_id" : 2, "name" : "Honest John Pizza",
"food" : [ "cheese pizza", "pepperoni pizza" ],
"beverages" : [ "soda" ]
} ]
}

간결한 상관 관계 하위 쿼리가 도입되기 전에는 다중 조인 수행 및 상관 관계 에 표시된 대로 pipeline $lookup 단계의$expr연산자에서 로컬 필드와 조인된 필드 간에$eq동등성 매치를 사용해야 했습니다. $lookup 을(를) 사용하여 하위 쿼리를 실행합니다.

이 예에서는 5.0 이전 버전의 구형 MongoDB 구문을 사용하며 버전에서 앞의 간결한 예와 동일한 결과를 반환합니다.

db.orders.aggregate( [
{
$lookup: {
from: "restaurants",
let: { orders_restaurant_name: "$restaurant_name",
orders_drink: "$drink" },
pipeline: [ {
$match: {
$expr: {
$and: [
{ $eq: [ "$$orders_restaurant_name", "$name" ] },
{ $in: [ "$$orders_drink", "$beverages" ] }
]
}
}
} ],
as: "matches"
}
}
] )

이전 예시는 다음 유사 SQL 문에 해당합니다.

SELECT *, matches
FROM orders
WHERE matches IN (
SELECT *
FROM restaurants
WHERE restaurants.name = orders.restaurant_name
AND restaurants.beverages = orders.drink
);

자세한 내용은 상관관계가 있는 하위 쿼리 성능 고려 사항을 참조하세요.

← $listSessions