내장된 문서로 일대다 관계 모델링하기
이 페이지의 내용
개요
이 페이지에서는 내장된 문서를 사용하여 연결된 데이터 간의 일대다 관계 를 설명하는 데이터 모델 에 대해 설명합니다. 연결된 데이터를 단일 문서 에 포함하면 데이터를 얻는 데 필요한 읽기 작업 수를 줄일 수 있습니다. 일반적으로 애플리케이션 이 한 번의 읽기 작업으로 필요한 모든 정보를 받을 수 있도록 스키마 를 구조화해야 합니다.
임베디드 문서 패턴
고객과 여러 주소 관계를 매핑하는 다음 예제를 살펴보겠습니다. 이 예는 다른 데이터 엔터티의 컨텍스트에서 많은 데이터 엔터티를 확인해야 하는 경우 참고보다 포함이 더 유리하다는 것을 보여줍니다. patron
와 address
데이터 간의 일대다 관계에서 patron
에는 여러 개의 address
엔터티가 있습니다.
정규화된 데이터 모델에서 address
문서에는 patron
문서에 대한 참조가 포함되어 있습니다.
// patron document { _id: "joe", name: "Joe Bookreader" } // address documents { patron_id: "joe", // reference to patron document street: "123 Fake Street", city: "Faketon", state: "MA", zip: "12345" } { patron_id: "joe", street: "1 Some Other Street", city: "Boston", state: "MA", zip: "12345" }
애플리케이션에서 name
정보가 포함된 address
데이터를 자주 조회하는 경우 애플리케이션에서 참고를 해결하기 위해 여러 번의 쿼리를 실행해야 합니다. 더 최적의 스키마는 다음 문서에서와 같이 address
데이터 엔터티를 patron
데이터에 포함하는 것입니다.
{ "_id": "joe", "name": "Joe Bookreader", "addresses": [ { "street": "123 Fake Street", "city": "Faketon", "state": "MA", "zip": "12345" }, { "street": "1 Some Other Street", "city": "Boston", "state": "MA", "zip": "12345" } ] }
포함된 데이터 모델을 사용하면 애플리케이션에서 한 번의 쿼리로 완전한 고객 정보를 조회할 수 있습니다.
서브세트 패턴
내장된 문서 패턴 의 잠재적인 문제는 특히 내장된 필드 가 바인딩되지 않은 경우 큰 문서로 이어질 수 있다는 점입니다. 이 경우 포함된 전체 데이터 설정하다 대신 서브세트 패턴 을 사용하여 애플리케이션 에 필요한 데이터에만 액세스 할 수 있습니다.
제품에 대한 리뷰 목록이 있는 전자상거래 사이트를 예로 들어 보겠습니다.
{ "_id": 1, "name": "Super Widget", "description": "This is the most useful item in your toolbox.", "price": { "value": NumberDecimal("119.99"), "currency": "USD" }, "reviews": [ { "review_id": 786, "review_author": "Kristina", "review_text": "This is indeed an amazing widget.", "published_date": ISODate("2019-02-18") }, { "review_id": 785, "review_author": "Trina", "review_text": "Nice product. Slow shipping.", "published_date": ISODate("2019-02-17") }, ... { "review_id": 1, "review_author": "Hans", "review_text": "Meh, it's okay.", "published_date": ISODate("2017-12-06") } ] }
리뷰는 시간 역순으로 정렬됩니다. 사용자가 제품 페이지를 방문하면 애플리케이션이 가장 최근의 리뷰 10개를 로드합니다.
모든 리뷰를 제품과 함께 저장하는 대신, 컬렉션을 두 개로 분할할 수 있습니다.
product
collection은 제품의 가장 최근 리뷰 10개를 포함하여 각 제품에 대한 정보를 저장합니다.{ "_id": 1, "name": "Super Widget", "description": "This is the most useful item in your toolbox.", "price": { "value": NumberDecimal("119.99"), "currency": "USD" }, "reviews": [ { "review_id": 786, "review_author": "Kristina", "review_text": "This is indeed an amazing widget.", "published_date": ISODate("2019-02-18") } ... { "review_id": 777, "review_author": "Pablo", "review_text": "Amazing!", "published_date": ISODate("2019-02-16") } ] } review
collection에는 모든 리뷰가 저장됩니다. 각 리뷰에는 리뷰가 작성된 제품에 대한 참고가 포함되어 있습니다.{ "review_id": 786, "product_id": 1, "review_author": "Kristina", "review_text": "This is indeed an amazing widget.", "published_date": ISODate("2019-02-18") } { "review_id": 785, "product_id": 1, "review_author": "Trina", "review_text": "Nice product. Slow shipping.", "published_date": ISODate("2019-02-17") } ... { "review_id": 1, "product_id": 1, "review_author": "Hans", "review_text": "Meh, it's okay.", "published_date": ISODate("2017-12-06") }
가장 최근 리뷰 10개를 product
collection에 저장하면 product
collection 호출 시 전체 데이터의 필수 하위 집합만 반환됩니다. 사용자가 추가 리뷰를 보고자 하는 경우 애플리케이션은 review
collection을 호출합니다.
팁
데이터를 분할할 위치를 고려할 때는 애플리케이션이 가장 먼저 로드하는 컬렉션에 가장 자주 액세스하는 데이터가 포함되어야 합니다. 이 예에서 ‑스키마는 애플리케이션에서 표시되는 리뷰 수의 기본값인 10개로 리뷰를 분할합니다.
하위 집합 패턴의 장단점
자주 액세스하는 데이터가 포함된 작은 문서를 사용하면 작업 세트의 전체 크기를 줄일 수 있습니다. 문서 크기가 작아지면 애플리케이션이 가장 자주 액세스하는 데이터의 읽기 성능이 향상됩니다.
그러나 서브세트 패턴은 데이터 중복을 초래합니다. 이 예제에서는 product
collection과 reviews
collection 모두에서 리뷰가 유지 관리됩니다. 각 collection 간에 리뷰의 일관성을 유지하려면 추가 단계를 수행해야 합니다. 예를 들어, 고객이 리뷰를 편집할 때 애플리케이션은 product
collection을 업데이트하는 것과 reviews
collection을 업데이트하는 두 가지 쓰기 작업을 수행해야 할 수 있습니다.
또한 애플리케이션에 로직을 구현하여 product
컬렉션의 리뷰가 항상 해당 제품에 대한 최신 리뷰 10개가 되도록 해야 합니다.
기타 샘플 사용 사례
제품 리뷰 외에도 서브세트 패턴도 저장에 적합할 수 있습니다.
블로그 포스트의 댓글 - 가장 최근 댓글 또는 가장 높은 평점의 댓글을 기본값으로 표시하려는 경우.
영화의 출연진 - 가장 큰 역할을 맡은 출연진을 기본값으로 표시하려는 경우