$lookup (집계)
이 페이지의 내용
정의
$lookup
버전 5.1에서 변경되었습니다.
동일한 데이터베이스의 컬렉션에 왼쪽 외부 조인을 수행하여 "조인된" 컬렉션의 문서를 필터링하여 처리합니다.
$lookup
단계에서는 각 입력 문서에 새 배열 필드를 추가합니다. 새 배열 필드에는 '조인'된 컬렉션에서 일치하는 문서들이 포함됩니다.$lookup
단계에서는 이렇게 재구성된 문서를 다음 단계로 넘깁니다.MongoDB 5.1부터 샤딩된 컬렉션에
$lookup
을 사용할 수 있습니다.서로 다른 두 컬렉션의 요소를 결합하려면
$unionWith
파이프라인 단계를 사용합니다.
호환성
다음 환경에서 호스팅되는 배포에 $lookup
사용할 수 있습니다.
MongoDB Atlas: 클라우드에서의 MongoDB 배포를 위한 완전 관리형 서비스
MongoDB Enterprise: MongoDB의 구독 기반 자체 관리 버전
MongoDB Community: MongoDB의 소스 사용 가능 무료 자체 관리 버전
구문
$lookup
단계의 구문은 다음과 같습니다.
단일 조인 조건으로 동일성 일치
입력 문서의 필드와 '조인된' 컬렉션의 문서 필드 간에 동등성 매치를 수행하려면 $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
다음과 같은 필드가 있는 문서를 받습니다.
필드 | 설명 |
---|---|
입력 문서에 추가할 새 배열 필드의 이름을 지정합니다. 새 배열 필드에는 |
이 작업은 다음과 같은 유사 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부터는 $lookup
파이프라인 단계에서 $sample
단계, $sampleRate
연산자 또는 $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
단계에서는 다음과 같은 필드가 있는 문서를 수락합니다.
필드 | 설명 |
---|---|
선택 사항. 파이프라인 단계에서 사용할 변수를 지정합니다. 변수 표현식을 사용하여 에 입력되는 조인된 컬렉션 문서의 필드에 액세스 파이프라인 단계에서 변수를 참조하려면 let 변수는 에 중첩된 추가 단계를
| |
조인된 컬렉션에서 실행할 에는 은 파이프라인 단계에서 변수를 참조하려면 let 변수는 에 중첩된 추가 단계를
| |
조인된 문서에 추가할 새 배열 필드의 이름을 지정합니다. 새 배열 필드에는 조인된 컬렉션에서 일치하는 문서가 포함됩니다. 지정한 이름이 조인된 문서에 이미 존재하는 경우 기존 필드를 덮어씁니다. |
이 작업은 다음과 같은 유사 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
은 다음과 같은 필드가 있는 문서를 수락합니다.
필드 | 설명 |
---|---|
외부 문서의 로컬 문서 에 | |
로컬 문서의 외부 문서 에 | |
선택 사항. 파이프라인 단계에서 사용할 변수를 지정합니다. 변수 표현식을 사용하여 에 입력되는 문서 필드에 액세스 파이프라인 단계에서 변수를 참조하려면 let 변수는 에 중첩된 추가 단계를
| |
외부 컬렉션에서 실행할 은(는) 파이프라인 단계에서 변수를 참조하려면 let 변수는 에 중첩된 추가 단계를
| |
외부 문서에 추가할 새 배열 필드의 이름을 지정합니다. 새 배열 필드에는 외부 컬렉션에서 일치하는 문서가 포함됩니다. 지정한 이름이 외부 문서에 이미 존재하는 경우 기존 필드를 덮어씁니다. |
이 작업은 다음과 같은 유사 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
등 여러 뷰가 포함된 집계를 수행하는 경우 반드시 뷰의 데이터 정렬이 동일해야 합니다.
제한 사항
$lookup
단계에는 $out
단계나 $merge
단계를 포함할 수 없습니다. 즉, 조인(join)된 컬렉션에 대한 파이프라인을 지정할 때 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> } }
Atlas Search 지원
MongoDB 6.0부터 $lookup
파이프라인에서 Atlas Search $search
또는 $searchMeta
단계를 지정하여 Atlas 클러스터에서 컬렉션을 검색할 수 있습니다. $search
또는 $searchMeta
단계는 $lookup
파이프라인 내의 첫 번째 단계여야 합니다.
예를 들어, 조인된 컬렉션에서 조건 및 하위 쿼리를 조인하거나 간결한 구문을 사용하여 상호 연관된 하위 쿼리를 실행하는 경우 아래와 같이 파이프라인에 $search
또는 $searchMeta
를 지정할 수 있습니다.
[{ "$lookup": { "from": <joined collection>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, "as": <output array field>, "pipeline": [{ "$search": { "<operator>": { <operator-specification> } }, ... }] } }]
[{ "$lookup": { "from": <joined collection>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, "as": <output array field>, "pipeline": [{ "$searchMeta": { "<collector>": { <collector-specification> } }, ... }] } }]
$search
를 사용한 $lookup
의 예를 보려면 $lookup을 사용하여 Atlas Search $search 쿼리 실행하기라는 Atlas Search 튜토리얼을 참조하세요.
샤드 컬렉션
MongoDB 5.1부터 $lookup
단계의 from
파라미터에서 샤딩된 컬렉션을 지정할 수 있습니다.
샤딩된 컬렉션을 대상으로 하는 동안 트랜잭션 내에서 $lookup
단계를 사용할 수 없습니다.
슬롯 기반 쿼리 실행 엔진
6.0버전부터 파이프라인의 모든 이전 단계가 슬롯 기반 실행 엔진에서도 실행될 수 있고 다음 조건 중 어느 것도 참이 아닌 경우 MongoDB는 슬롯 기반 실행 쿼리 엔진을 사용하여 $lookup
단계를 실행할 수 있습니다.
$lookup
작업은 조인된 컬렉션에서 파이프라인을 실행합니다. 이러한 종류의 작업 예시를 보려면 조인된 컬렉션의 조인 조건 및 하위 쿼리를 참조하세요.$lookup
의localField
또는foreignField
는 숫자 구성 요소를 지정합니다. 예시:{ localField: "restaurant.0.review" }
파이프라인에서
$lookup
의from
필드는 뷰 또는 샤드 컬렉션을 지정합니다.
자세한 내용은 $lookup
최적화를 참조하세요.
성능 고려 사항
$lookup
성능은 수행되는 작업 유형에 따라 달라집니다. 다양한 $lookup
작업에 대한 성능 고려 사항은 다음 표를 참조하세요.
$lookup 작업 | 성능 고려 사항 |
---|---|
| |
| |
|
일반적인 성능 전략은 인덱싱 전략 및 쿼리 최적화를 참조하세요.
중요
쿼리 내에서 $lookup
을 과도하게 사용하면 성능이 저하될 수 있습니다. 여러 $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 );
자세한 내용은 동등성 매치 성능 고려 사항을 참조하세요.
배열에 $lookup
사용
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
과 함께 $lookup
사용
$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
를 사용하여 items
와 orders
에서 조인된 문서를 병합합니다.
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 }
다중 조인 조건 및 상관관계 하위 쿼리 사용
파이프라인은 조인된 컬렉션에서 실행할 수 있으며 여러 조인 조건을 포함할 수 있습니다. $expr
연산자를 사용하면 접속사 및 비동등성 매치를 포함한 더 복잡한 조인 조건이 가능합니다.
조인 조건은 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.item
및warehouse.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 );
$expr
연산자에 배치된 $eq
, $lt
, $lte
, $gt
, $gte
비교 연산자는 $lookup
단계에서 참조된 from
컬렉션의 인덱스를 사용할 수 있습니다. 제한 사항:
인덱스는 필드와 상수 간의 비교에만 사용할 수 있으므로
let
피연산자는 상수로 해결되어야 합니다.예를 들어
$a
및 상수 값 간의 비교에는 인덱스를 사용할 수 있지만,$a
및$b
간의 비교에는 인덱스를 사용할 수 없습니다.let
피연산자가 비어 있거나 누락된 값으로 확인되는 비교에는 인덱스가 사용되지 않습니다.다중 키 인덱스 는 사용되지 않습니다.
예를 들어 warehouses
컬렉션에 인덱스 { stock_item: 1, instock: 1 }
가 존재하는 경우입니다.
warehouses.stock_item
필드의 동등성 매치는 인덱스를 사용합니다.warehouses.instock
필드에 대한 쿼리의 범위 부분도 복합 인덱스의 인덱스 필드를 사용합니다.
상관관계가 없는 하위 쿼리 수행하기 - $lookup
집계 파이프라인 $lookup
단계는 조인된 컬렉션에서 파이프라인을 실행할 수 있으며, 이는 상호 관련되지 않은 하위 쿼리를 허용합니다. 상호 관련되지 않은 하위 쿼리는 조인된 문서 필드를 참조하지 않습니다.
참고
MongoDB 5.0부터는 $lookup
파이프라인 단계에서 $sample
단계, $sampleRate
연산자 또는 $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 );
자세한 내용은 상관관계가 없는 하위 쿼리 성능 고려 사항을참조하세요.
상관관계가 있는 간결한 하위 쿼리 수행하기 - $lookup
버전 5.0에 추가.
MongoDB 5.0부터 집계 파이프라인 $lookup
단계는 컬렉션 간의 조인을 개선하는 간결한 상관관계 하위 쿼리 구문을 지원합니다. 새로운 간결한 구문은 $match
단계에서 $expr
연산자 내부의 외부 및 로컬 필드에 대한 동등성 매치 요구 사항을 제거합니다.
컬렉션 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
localField를restaurants.name
foreignField와 매칭시켜orders
와restaurants
컬렉션을 조인합니다.pipeline
이 실행되기 전에 매치가 수행됩니다.각각
$$orders_drink
및$beverages
를 사용하여 액세스하는orders.drink
및restaurants.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.drink
및 restaurants.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
동등성 매치를 사용해야 했습니다.
이 예에서는 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 );
자세한 내용은 상관관계가 있는 하위 쿼리 성능 고려 사항을 참조하세요.