$lookup
작업 축소
개요
$lookup
작업은 지정된 필드를 기반으로 동일한 데이터베이스에 있는 두 컬렉션의 데이터를 결합합니다. $lookup
작업은 데이터가 관계형 데이터베이스와 유사하게 구조화되어 있고 대규모 계층적 데이터 세트를 모델링해야 할 때 유용할 수 있습니다. 그러나 이러한 작업은 단일 컬렉션이 아닌 두 개의 컬렉션에서 로직을 읽고 수행해야 하기 때문에 속도가 느리고 리소스 집약적일 수 있습니다.
$lookup
작업을 자주 실행하는 경우 애플리케이션이 단일 컬렉션을 쿼리하여 필요한 모든 정보를 얻을 수 있도록 스키마를 재구성하는 것이 좋습니다. 내장된 문서 및 배열이 있는 MongoDB의 유연한 스키마 모델 을 활용하여 단일 문서 구조에서 데이터 간의 관계를 캡처할 수 있습니다. 이 비정규화된 모델 을 사용하면 MongoDB의 풍부한 문서를 활용하고 애플리케이션에서 단일 쿼리로 관련 데이터를 검색하고 조작할 수 있습니다.
예시
다음 예제에서는 $lookup
작업을 줄이기 위해 설계된 두 가지 스키마 구조를 보여줍니다.
내장된 문서 사용
식료품점이 두 개의 개별 컬렉션에서 일대일 재고 및 영양 정보를 추적하는 다음 예를 생각해 보세요. 각 재고 항목은 고유한 영양 성분 항목에 해당합니다. nutrition_id
필드는 테이블 형식 데이터베이스와 유사하게 inventory
컬렉션을 nutrition_facts
컬렉션에 연결합니다.
// inventory collection { "name": "Pear", "stock": 20, "nutrition_id": 123, // reference to a nutrition_fact document ... } { "name": "Candy Bar", "stock": 26, "nutrition_id": 456, ... }
// nutrition_facts collection { "_id": 123, "calories": 100, "grams_sugar": 17, "grams_protein": 1, ... } { "_id": 456, "calories": 250, "grams_sugar": 27, "grams_protein": 4, ... }
애플리케이션이 name
(으)로 재고 항목에 대한 영양 정보를 요청하는 경우, 이 스키마 구조는 재고 항목의 nutrition_id
와 일치하는 항목을 찾기 위해 nutrition_facts
컬렉션의 $lookup
가 필요합니다.
대신 inventory
컬렉션에 영양 정보를 포함할 수 있습니다.
// inventory collection { "name": "Pear", "stock": 20, "nutrition_facts": { "calories": 100, "grams_sugar": 17, "grams_protein": 1, ... } ... } { "name": "Candy Bar", "stock": 26, "nutrition_facts": { "calories": 250, "grams_sugar": 27, "grams_protein": 4, ... } ... }
이렇게 하면 inventory
에서 항목을 쿼리할 때 다른 쿼리나 $lookup
작업 없이도 영양 정보가 결과에 포함됩니다. 컬렉션 전체의 데이터가 일대일 관계에 있는 경우 문서 포함을 고려하세요.
배열 사용
표 형식 데이터베이스와 유사하게 야구 리그의 players
컬렉션에 있는 문서가 teams
컬렉션에 있는 문서를 참조하는 다음 예를 생각해 보세요:
// players collection { "team_id": 1, // reference to a team document "name": "Nick", "position": "Pitcher" ... } { "team_id": 1, "name": "Anuj", "position": "Shortstop" ... }
// teams collection { "_id": 1, "name": "Danbury Dolphins" ... }
애플리케이션이 팀의 선수 목록을 요청하는 경우, 이 스키마 구조는 team_id
와 일치하는 각 선수를 찾기 위해 players
컬렉션의 $lookup
가 필요합니다.
대신 팀 문서 자체의 배열에 players
을(를) 나열할 수 있습니다.
// teams collection { "_id": 1, "name": "Danbury Dolphins", "players": [ { "name": "Nick", "position": "Pitcher" ... }, { "name": "Anuj", "position": "Shortstop" ... } ] }
배열을 사용하여 관련 데이터를 보유함으로써 애플리케이션은 $lookup
작업이나 다른 컬렉션에 대한 인덱스 없이도 해당 팀의 선수를 포함한 전체 team
정보를 검색할 수 있습니다. 이 경우 정보를 별도의 컬렉션에 저장하는 것보다 배열을 사용하는 것이 더 효율적입니다.
참고
위의 예에서 야구팀에는 정해진 수의 선수가 있으며 배열이 지나치게 커질 위험은 없습니다.
배열 고려 사항
대규모 배열을 읽고 쓰는 데 드는 성능 비용은 $lookup
작업을 피함으로써 얻는 이점보다 클 수 있습니다. 배열이 제한되지 않거나 지나치게 큰 경우 해당 배열은 읽기 및 쓰기 성능을 저하시킬 수 있습니다.
배열에 인덱스를 생성하면 배열의 각 요소에 인덱스가 지정됩니다. 해당 배열에 자주 쓰면 잠재적으로 큰 배열 필드를 인덱싱하거나 다시 인덱싱하는 것은 중요할 수 있습니다.
비정규화
스키마를 비정규화하는 것은 필드를 복제하거나 기존 필드에서 새 필드를 파생시키는 프로세스입니다. 비정규화는 다음과 같은 다양한 경우에 읽기 성능을 향상시킬 수 있습니다.
반복 쿼리에는 다른 컬렉션에 있는 큰 문서의 몇 가지 필드가 필요합니다. 두 개의 서로 다른 컬렉션을 병합하거나
$lookup
작업을 자주 수행하지 않도록 반복 쿼리 대상 컬렉션의 내장된 문서에 해당 필드의 복사본을 유지하도록 선택할 수 있습니다.collection에 있는 일부 필드의 평균 값이 요청되는 경우가 많습니다. 쓰기의 일부로 업데이트되고 해당 필드의 실행 평균을 유지 관리하는 별도의 collection에 파생된 필드를 생성하도록 선택할 수 있습니다.
관련 데이터를 그룹화할 때는 문서나 배열을 중복 없이 포함하는 것이 선호되지만, 별도의 collection을 유지해야 하는 경우에는 비정규화를 통해 읽기 성능을 개선할 수 있습니다.
참고
스키마를 비정규화하면 일관적인 중복 데이터를 유지 관리하는 것은 사용자의 책임이 됩니다.
자세히 알아보기
스키마에 가장 적합한 구조는 애플리케이션의 컨텍스트에 따라 다릅니다. 다음 리소스에서는 데이터 모델링에 대한 자세한 정보와 내장된 문서 및 배열에 대한 사용 사례를 더 확인할 수 있습니다.
데이터 모델
MongoDB의 데이터 모델링과 유연한 스키마 모델에 대해 자세히 알아보려면 데이터 모델링 소개를 참조하세요.
포함된 데이터 모델과 정규화된 데이터 모델 간의 장단점에 대해 자세히 알아보려면 데이터 모델 설계를 참조하세요.
MongoDB는 또한 데이터 모델링에 대한 무료 MongoDB 대학 과정: MongoDB용 데이터 모델링을 제공합니다.
MongoDB.live 2020 데이터 모델링 프레젠테이션
유연한 데이터 모델을 스키마에 통합하는 방법을 알아보려면 MongoDB.live 2020의 다음 프레젠테이션을 참조하세요:
MongoDB의엔티티 관계에 대해 알아보고, MongoDB를 사용한 데이터 모델링으로 구현한 예시를 살펴보세요.
고급 스키마 설계 패턴을 통해 스키마에 통합할 수 있는 고급 데이터 모델링 디자인 패턴에 대해 알아보세요.
배열
MongoDB에서 배열을 쿼리하는 방법에 대해 자세히 알아보려면 배열 쿼리를 참조하세요.
디자인 패턴
배열이 잘 작동하는 상황에 대해 알아보려면 다음 디자인 패턴을 참조하세요.
비정규화된 스키마
데이터를 복제하여 스키마를 개선하는 상황에 대해 읽어 보려면 다음 디자인 패턴을 참조하세요.
확장 참조 패턴을 사용해 자주 읽는 데이터의 일부를 큰 문서에서 작은 문서로 복제할 수 있습니다.