MongoDB에서 문서 스키마를 설계하는 방법

저자는 Write for DOnations 프로그램의 일환으로 Open Internet/Free Speech Fund에 기부금을 전달하기로 선택했습니다.

서론

관계형 데이터베이스 작업 경험이 많다면 테이블과 관계 등 관계형 모델의 원칙을 넘어서기 어려울 수 있습니다. MongoDB와 같은 문서 지향 데이터베이스는 관계형 모델의 경직성과 제한에서 벗어날 수 있게 해줍니다. 그러나 데이터베이스에 자기 설명적인 문서를 저장할 수 있는 유연성과 자유로움은 다른 함정과 어려움을 초래할 수 있습니다.

이 개념적 글은 문서 지향 데이터베이스의 스키마 설계와 관련된 다섯 가지 일반적인 지침을 개괄하고, 데이터 간의 관계를 모델링할 때 고려해야 할 다양한 사항을 강조합니다. 또한 배열 내에 문서를 포함시키고 자식 및 부모 참조를 사용하는 등 관계를 모델링하기 위해 사용할 수 있는 여러 전략을 살펴보고, 이러한 전략이 가장 적절한 사용 시기를 설명합니다.

가이드라인 1 — 함께 접근해야 할 데이터는 함께 저장하기

일반적인 관계형 데이터베이스에서 데이터는 테이블에 저장되며, 각 테이블은 엔티티, 객체 또는 이벤트를 구성하는 다양한 속성을 나타내는 고정된 열 목록으로 구성됩니다. 예를 들어, 대학교의 학생들을 나타내는 테이블에서는 각 학생의 이름, 성, 생년월일 및 고유 식별 번호를 보유하는 열을 찾을 수 있습니다.

일반적으로 각 테이블은 단일 주제를 나타냅니다. 학생의 현재 학업, 장학금 또는 이전 교육에 대한 정보를 저장하려는 경우, 개인 정보를 보유하는 테이블과 별도의 테이블에 해당 데이터를 보관하는 것이 합리적일 수 있습니다. 그런 다음 이러한 테이블을 연결하여 각 테이블의 데이터 간에 관계가 있음을 나타낼 수 있으며, 이는 포함된 정보가 의미 있는 연결이 있음을 나타냅니다.

예를 들어, 각 학생의 장학금 상태를 설명하는 테이블은 학생 ID 번호로 학생을 참조할 수 있지만, 학생의 이름이나 주소를 직접 저장하지 않아 데이터 중복을 피할 수 있습니다. 이런 경우, 학생의 소셜 미디어 계정, 이전 교육 및 장학금에 대한 모든 정보를 얻기 위해서는 한 번에 둘 이상의 테이블에 접근하여 여러 테이블의 결과를 하나로 취합해야 합니다.

이러한 참조를 통한 관계 설명 방법을 정규화된 데이터 모델이라고 합니다. 이런 방식으로 데이터를 저장하는 것은 문서 지향 데이터베이스에서도 가능합니다. 그러나 문서 모델의 유연성과 단일 문서 내에 포함된 문서와 배열을 저장할 수 있는 자유로움은 관계형 데이터베이스와는 다르게 데이터를 모델링할 수 있게 합니다.

문서 지향 데이터베이스에서 데이터 모델링의 기본 개념은 “함께 접근될 것들을 함께 저장하라”입니다.” 학생 예시를 더 들어보면, 이 학교의 대부분의 학생들이 둘 이상의 이메일 주소를 가지고 있습니다. 이런 이유로 대학에서는 각 학생의 연락처 정보와 함께 여러 이메일 주소를 저장할 수 있는 기능을 원합니다.

이런 경우, 예시 문서는 다음과 같은 구조를 가질 수 있습니다:

{
    "_id": ObjectId("612d1e835ebee16872a109a4"),
    "first_name": "Sammy",
    "last_name": "Shark",
    "emails": [
        {
            "email": "[email protected]",
            "type": "work"
        },
        {
            "email": "[email protected]",
            "type": "home"
        }
    ]
}

이 예시 문서에는 포함된 이메일 주소 목록이 포함되어 있습니다.

하나의 문서 내에서 단일 주제 이상을 표현하는 것은 비정규화된 데이터 모델의 특징입니다. 이를 통해 애플리케이션은 여러 개의 개별 객체 및 컬렉션에 접근할 필요 없이 주어진 객체(여기서는 학생)에 대한 모든 관련 데이터를 한 번에 검색하고 조작할 수 있습니다. 또한 이러한 문서에 대한 작업의 원자성을 보장하며, 무결성을 보장하기 위해 다중 문서 트랜잭션을 사용할 필요가 없습니다.

내장된 문서를 사용하여 함께 접근해야 하는 데이터를 함께 저장하는 것은 문서 지향 데이터베이스에서 데이터를 표현하는 최적의 방법입니다. 다음 지침에서는 일대일 또는 일대다와 같은 객체 간의 다양한 관계를 문서 지향 데이터베이스에서 가장 잘 모델링할 수 있는 방법을 배우게 될 것입니다.

지침 2 — 내장 문서를 사용한 일대일 관계 모델링

일대일 관계는 두 가지 서로 다른 객체 사이의 연결을 나타내며, 하나의 객체가 다른 종류의 정확히 하나의 객체와 연결되어 있습니다.

이전 섹션의 학생 예시를 계속 살펴보면, 각 학생은 언제든지 하나의 유효한 학생증을 가지고 있습니다. 한 카드는 여러 학생에게 속하지 않으며, 어떤 학생도 여러 신분증을 가질 수 없습니다. 이 모든 데이터를 관계형 데이터베이스에 저장한다면, 학생 기록과 학생증 기록을 참조를 통해 연결된 별도의 테이블에 저장하여 학생과 그들의 학생증 사이의 관계를 모델링하는 것이 합리적일 것입니다.

문서 데이터베이스에서 이러한 관계를 표현하는 일반적인 방법은 내장 문서를 사용하는 것입니다. 예를 들어, 다음 문서는 Sammy라는 학생과 그들의 학생증을 설명합니다:

{
    "_id": ObjectId("612d1e835ebee16872a109a4"),
    "first_name": "Sammy",
    "last_name": "Shark",
    "id_card": {
        "number": "123-1234-123",
        "issued_on": ISODate("2020-01-23"),
        "expires_on": ISODate("2020-01-23")
    }
}

이 예시 문서의 id_card 필드는 단일 값 대신 학생의 신분증을 나타내는 내장 문서를 보유하고 있음을 주목하세요. 신분증은 실제로는 별도의 객체이지만, 학생 Sammy를 설명하는 문서의 일부가 됩니다. 일반적으로 이런 식으로 문서 스키마를 구성하여 단일 쿼리를 통해 모든 관련 정보를 검색할 수 있는 것은 타당한 선택입니다.

한 종류의 객체가 다른 종류의 여러 객체와 연결되는 관계를 만나게 되면, 예를 들어 학생의 이메일 주소, 참석하는 과목 또는 학생회 게시판에 게시하는 메시지와 같은 경우, 상황이 덜 직관적으로 변합니다. 다음 몇 가지 가이드라인에서는 이러한 데이터 예시를 사용하여 일대다 및 다대다 관계를 다루는 다양한 접근 방식을 배우게 될 것입니다.

지침 3 — 임베디드 문서로 일대다 관계 모델링

한 유형의 객체가 다른 유형의 여러 객체와 관련되어 있을 때 이를 일대다 관계로 설명할 수 있습니다. 학생은 여러 개의 이메일 주소를 가질 수 있고, 자동차는 수많은 부품을 가질 수 있으며, 쇼핑 주문은 여러 항목으로 구성될 수 있습니다. 이러한 예들은 모두 일대다 관계를 나타냅니다.

문서 데이터베이스에서 일대일 관계를 나타내는 가장 일반적인 방법은 임베디드 문서를 통하지만, 문서 스키마에서 일대다 관계를 모델링하는 여러 가지 방법이 있습니다. 이러한 관계를 가장 잘 모델링하는 방법에 대해 고려할 때, 다음과 같은 세 가지 관계의 속성을 고려해야 합니다:

  • 카디널리티: 카디널리티는 주어진 집합에 있는 개별 요소의 수를 측정한 것입니다. 예를 들어, 한 반에 30명의 학생이 있다면 그 반의 카디널리티는 30이라고 할 수 있습니다. 일대다 관계에서 카디널리티는 각 경우마다 다를 수 있습니다. 학생은 하나의 이메일 주소를 가질 수도 있고 여러 개를 가질 수도 있습니다. 몇 개의 수업에만 등록되어 있거나 완전히 꽉 찬 일정을 가질 수도 있습니다. 일대다 관계에서 “다”의 크기는 데이터 모델링 방법에 영향을 줄 수 있습니다.
  • 독립적 접근: 일부 관련 데이터는 주요 객체와 별도로 접근하는 경우가 드물 것입니다. 예를 들어, 학생의 이메일 주소를 다른 학생 정보 없이 검색하는 것은 일반적이지 않을 수 있습니다. 반면에, 대학의 강좌는 등록된 학생이나 학생들과 상관없이 개별적으로 접근하고 업데이트해야 할 수 있습니다. 관련 문서를 혼자 접근할 것인지 여부도 데이터 모델링에 영향을 미칠 것입니다.
  • 데이터 간의 관계가 엄격한 일대다 관계인지 여부: 대학에서 학생이 수강하는 강좌를 예로 들어보겠습니다. 학생의 관점에서 여러 강좌에 참여할 수 있습니다. 겉으로 보기에 이것은 일대다 관계처럼 보일 수 있습니다. 그러나 대학 강좌는 단일 학생이 참석하는 경우는 드물고, 대부분 여러 학생이 동일한 수업을 듣습니다. 이런 경우, 관련된 관계는 실제로 일대다 관계가 아니라 다대다 관계이므로, 일대다 관계와는 다른 방식으로 이 관계를 모델링해야 합니다.

학생의 이메일 주소를 어떻게 저장할지 결정한다고 상상해보세요. 각 학생은 업무용, 개인용, 대학에서 제공하는 이메일 주소와 같은 여러 이메일 주소를 가질 수 있습니다. 단일 이메일 주소를 나타내는 문서는 다음과 같은 형식을 취할 수 있습니다:

{
    "email": "[email protected]",
    "type": "work"
}

카디널리티 측면에서, 각 학생당 이메일 주소는 몇 개에 불과할 것입니다. 학생이 수십 개, 더 나아가 수백 개의 이메일 주소를 가질 가능성은 낮기 때문입니다. 따라서 이러한 관계는 일대소수 관계로 특징지어질 수 있으며, 이는 이메일 주소를 학생 문서에 직접 포함시키고 함께 저장하는 강력한 이유가 됩니다. 이메일 주소 목록이 무한정 커져 문서가 커지고 사용하기 어려워지는 위험을 감수하지 않아도 됩니다.

주의: 배열에 데이터를 저장하는 것과 관련된 몇 가지 위험 요소가 있음을 알아두세요. 예를 들어, 단일 MongoDB 문서의 크기는 16MB를 초과할 수 없습니다. 배열 필드를 사용하여 여러 문서를 포함하는 것은 가능하고 일반적이지만, 객체 목록이 제어 불가능하게 커질 경우 문서가 이 크기 제한에 빠르게 도달할 수 있습니다. 또한, 포함된 배열 내에 많은 양의 데이터를 저장하면 쿼리 성능에 큰 영향을 미칩니다.

배열 필드에 여러 문서를 포함하는 것은 많은 상황에서 적합할 수 있지만, 항상 최선의 해결책이라고 할 수는 없습니다.

독립적인 접근 측면에서, 이메일 주소는 학생과 별도로 접근될 가능성이 낮습니다. 따라서 이들을 별도의 컬렉션에 별도의 문서로 저장할 명확한 동기가 없습니다. 이것은 이메일 주소를 학생의 문서 내에 포함시키는 또 다른 강력한 이유입니다.

고려해야 할 마지막 사항은 이 관계가 실제로 다대다 관계가 아닌 일대다 관계인지 여부입니다. 이메일 주소는 한 사람에게 속하기 때문에 이 관계를 다대다 관계가 아닌 일대다 관계(또는 더 정확하게는 일대소수 관계)로 설명하는 것이 합리적입니다.

이 세 가지 가정은 학생 자체를 설명하는 동일한 문서 내에 학생들의 다양한 이메일 주소를 포함하는 것이 이러한 종류의 데이터를 저장하기 위한 좋은 선택이 될 것이라고 제안합니다. 이메일 주소가 포함된 샘플 학생 문서는 다음과 같은 형태를 취할 수 있습니다:

{
    "_id": ObjectId("612d1e835ebee16872a109a4"),
    "first_name": "Sammy",
    "last_name": "Shark",
    "emails": [
        {
            "email": "[email protected]",
            "type": "work"
        },
        {
            "email": "[email protected]",
            "type": "home"
        }
    ]
}

이 구조를 사용하면 학생의 문서를 검색할 때마다 동일한 읽기 작업에서 포함된 이메일 주소도 검색됩니다.

관련 문서가 독립적으로 액세스될 필요가 없는 일대소수 종류의 관계를 모델링할 때 이와 같이 문서를 직접 포함하는 것이 일반적으로 바람직합니다. 이는 스키마의 복잡성을 줄일 수 있기 때문입니다.

그러나 앞서 언급했듯이 이와 같이 문서를 포함하는 것이 항상 최적의 솔루션은 아닙니다. 다음 섹션에서는 일부 시나리오에서 이러한 경우가 왜 그럴 수 있는지에 대한 자세한 내용을 제공하고, 문서 데이터베이스에서 관계를 나타내는 대체 방법으로 자식 참조를 사용하는 방법을 설명합니다.

가이드라인 4 – 자식 참조를 사용한 일대다 및 다대다 관계 모델링

학생과 이메일 주소 간의 관계의 특성은 문서 데이터베이스에서 그 관계를 가장 잘 모델링할 수 있는 방법을 알려주었습니다. 이것은 학생과 참석하는 과정 간의 관계와는 몇 가지 차이점이 있으므로, 학생과 과정 간의 관계를 모델링하는 방법도 다를 것입니다.

학생이 참석하는 단일 과정을 설명하는 문서는 다음과 같은 구조를 따를 수 있습니다:

{
    "name": "Physics 101",
    "department": "Department of Physics",
    "points": 7
}

예를 들어, 각 학생의 과정에 대한 정보를 내장 문서를 사용하여 저장하기로 결정했다고 가정해 봅시다:

{
    "_id": ObjectId("612d1e835ebee16872a109a4"),
    "first_name": "Sammy",
    "last_name": "Shark",
    "emails": [
        {
            "email": "[email protected]",
            "type": "work"
        },
        {
            "email": "[email protected]",
            "type": "home"
        }
    ],
    "courses": [
        {
            "name": "Physics 101",
            "department": "Department of Physics",
            "points": 7
        },
        {
            "name": "Introduction to Cloud Computing",
            "department": "Department of Computer Science",
            "points": 4
        }
    ]
}

이것은 완벽하게 유효한 MongoDB 문서가 될 것이며, 목적에 잘 부합할 수 있지만, 이전 가이드라인에서 배운 세 가지 관계 속성을 고려해 보세요.

첫 번째는 카디널리티입니다. 학생은 아마도 몇 개의 이메일 주소만을 유지할 것이지만, 여러 과정에 참석할 수 있습니다. 몇 년 동안의 출석 후에는 학생이 참여한 수십 개의 과정이 있을 수 있습니다. 또한, 그들은 이러한 과정을 다른 많은 학생들과 함께 참석할 것이며, 그들도 자신의 연수 기간 동안 자신의 과정 세트에 참석할 것입니다.

코스를 이전 예제와 같이 내장하도록 결정한 경우, 학생의 문서는 매우 빠르게 규모가 커질 것입니다. 높은 차원수에서는 내장된 문서 접근법이 덜 타당해집니다.

두 번째 고려사항은 독립적 접근입니다. 이메일 주소와 달리, 대학 강좌에 대한 정보가 별도로 검색되어야 하는 경우가 있을 것이라는 것은 논리적입니다. 예를 들어, 마케팅 프로모션 소닉을 준비하기 위해 사용 가능한 강좌 정보가 필요한 경우가 있습니다. 또한, 강좌는 시간이 지남에 따라 업데이트되어야 할 가능성이 큽니다 : 강좌를 맡고 있는 교수가 변하거나, 일정이 변동되거나, 필수 과목이 업데이트되어야 할 수 있습니다.

강좌를 학생 문서 내에 내장된 문서로 저장하려 한다면, 대학에서 제공하는 모든 강좌 목록을 검색하는 것이 번거로울 것입니다. 또한, 강좌가 업데이트되어야 할 때마다, 모든 학생 기록을 통해 강좌 정보를 업데이트해야 합니다. 이 두 가지는 강좌를 별도로 저장하고 내장하지 않는 이유가 됩니다.

세 번째 고려사항은 학생과 대학 강좌 간의 관계가 실제로 일대다인가, 아니면 다대다인가입니다. 이 경우는后者입니다. 하나의 강좌에 여러 학생이 수강할 수 있기 때문입니다. 이 관계의 차원수와 독립적 접근 측면은 각 강좌 문서를 내장하는 것을 반대하는 주요 이유입니다. 접근 및 업데이트의 쉽게함과 같은 실용적 이유뿐만 아니라, 강좌와 학생 간의 다대다적인 관계를 고려할 때, 강좌 문서를 별도의 컬렉션에 저장하고 고유한 식별자를 부여하는 것이 의미 있을 수 있습니다.

이 별도 컬렉션에서 클래스를 나타내는 문서는 다음 예시들과 같은 구조를 가질 수 있습니다:

{
    "_id": ObjectId("61741c9cbc9ec583c836170a"),
    "name": "Physics 101",
    "department": "Department of Physics",
    "points": 7
},
{
    "_id": ObjectId("61741c9cbc9ec583c836170b"),
    "name": "Introduction to Cloud Computing",
    "department": "Department of Computer Science",
    "points": 4
}

이러한 방식으로 강의 정보를 저장하게 되면, 학생들이 어떤 강의를 듣는지 알기 위해 학생들과 강의를 연결할 방법을 찾아야 합니다. 관련 객체의 수가 과도히 많지 않은 경우, 특히 많이-많이 관계가 있는 경우, 이러한 경우에는 자식 참조를 사용하는 것이 일반적입니다.

자식 참조를 사용하면, 학생의 문서는 학생이 수강하는 강의의 객체 식별자를 내장된 배열에 참조하게 됩니다. 이 예시에서와 같이 됩니다:

{
    "_id": ObjectId("612d1e835ebee16872a109a4"),
    "first_name": "Sammy",
    "last_name": "Shark",
    "emails": [
        {
            "email": "[email protected]",
            "type": "work"
        },
        {
            "email": "[email protected]",
            "type": "home"
        }
    ],
    "courses": [
        ObjectId("61741c9cbc9ec583c836170a"),
        ObjectId("61741c9cbc9ec583c836170b")
    ]
}

이 예시 문서는 여전히 courses 필드를 가지고 있으며, 이것은 배열입니다. 하지만 이전 예시처럼 전체 강의 문서를 내장하는 것이 아니라, 별도 컬렉션에 있는 강의 문서를 참조하는 식별자만 내장됩니다. 이제 학생 문서를 검색할 때, 강의는 즉시 사용할 수 없고 별도로 쿼리해야 합니다. 반면, 어떤 강의를 검색해야 하는지는 즉시 알 수 있습니다. 또한, 강의의 세부 정보가 업데이트되어야 하는 경우, 강의 문서 자체만 변경해야 합니다. 학생과 강의 간의 모든 참조는 유효합니다.

참고: 관계의 카디널리티가 이러한 방식으로 자식 참조를 내장할 때 너무 큰지에는 강력한 규칙이 없습니다. 어플리케이션이 가장 적합한 방식인지에 따라 낮은 카디널리티나 높은 카디널리티에서 다른 접근 방식을 선택할 수 있습니다. 결국, 어플리케이션이 쿼리하고 업데이트하는 방식에 맞게 데이터 구조를 설정하고 싶을 것입니다.

한 대다수 관계를 모델링할 때 관련 문서의 양이 적절한 범위 내에 있고 관련 문서들이 독립적으로 접근되어야 한다면, 관련 문서를 별도로 저장하고 자식 참조를 사용하여 연결하는 것을 선호하세요.

이제 서로 다른 유형의 데이터 간의 관계를 나타내기 위해 자식 참조를 사용하는 방법을 배웠으니, 이 가이드는 역으로 부모 참조라는 개념을 설명할 것입니다.

가이드라인 5 — 부모 참조를 사용한 무제한 일대다 관계 모델링

자식 참조는 관련 객체가 너무 많아서 부모 문서 내에 직접 포함시키기 어려울 때 잘 작동하지만, 그 양은 여전히 알려진 범위 내에 있습니다. 그러나 연결된 문서의 수가 무제한이고 시간이 지남에 따라 계속 증가할 수 있는 경우도 있습니다.

예를 들어, 대학교 학생회에서 누구나 수업에 대한 질문, 여행 이야기, 구인 공고, 학습 자료 또는 그냥 자유로운 대화 등 원하는 메시지를 게시할 수 있는 게시판이 있다고 상상해보세요. 이 예제의 샘플 메시지는 제목과 메시지 본문으로 구성됩니다:

{
    "_id": ObjectId("61741c9cbc9ec583c836174c"),
    "subject": "Books on kinematics and dynamics",
    "message": "Hello! Could you recommend good introductory books covering the topics of kinematics and dynamics? Thanks!",
    "posted_on": ISODate("2021-07-23T16:03:21Z")
}

이 관계를 모델링하기 위해 이전에 논의한 두 가지 접근 방식 중 하나 — 포함 또는 자식 참조 — 를 사용할 수 있습니다. 포함을 선택하기로 결정한다면, 학생의 문서는 다음과 같은 형태를 취할 수 있습니다:

{
    "_id": ObjectId("612d1e835ebee16872a109a4"),
    "first_name": "Sammy",
    "last_name": "Shark",
    "emails": [
        {
            "email": "[email protected]",
            "type": "work"
        },
        {
            "email": "[email protected]",
            "type": "home"
        }
    ],
    "courses": [
        ObjectId("61741c9cbc9ec583c836170a"),
        ObjectId("61741c9cbc9ec583c836170b")
    ],
    "message_board_messages": [
        {
            "subject": "Books on kinematics and dynamics",
            "message": "Hello! Could you recommend good introductory books covering the topics of kinematics and dynamics? Thanks!",
            "posted_on": ISODate("2021-07-23T16:03:21Z")
        },
        . . .
    ]
}

하지만, 만약 학생이 메시지 작성에 능숙하다면 그들의 문서는 빠르게 엄청나게 길어져서 16MB 크기 제한을 쉽게 초과할 수 있으므로, 이 관계의 카디널리티는 내장을 반대하는 것을 제안합니다. 또한, 메시지는 학생과 별도로 접근될 필요가 있을 수 있으며, 메시지 게시판 페이지가 학생들이 최근에 게시한 메시지를 보여주도록 설계된 경우에 그럴 수 있습니다. 이것은 또한 이 시나리오에서 내장이 최선의 선택이 아니라는 것을 제안합니다.

참고: 학생의 문서를 검색할 때 메시지 게시판 메시지에 자주 접근하는지도 고려해야 합니다. 그렇지 않다면, 그 메시지들이 모두 문서 안에 내장되어 있을 경우, 메시지 목록이 자주 사용되지 않더라도 이 문서를 검색하고 조작할 때 성능 저하를 유발할 것입니다. 관련 데이터에 대한 드문 접근은 종종 문서를 내장하지 말아야 한다는 또 다른 신호입니다.

이제 이전 예제처럼 전체 문서를 내장하는 대신 자식 참조를 사용하는 것을 고려해 보십시오. 개별 메시지는 별도의 컬렉션에 저장되고, 학생의 문서는 다음과 같은 구조를 가질 수 있습니다:

{
    "_id": ObjectId("612d1e835ebee16872a109a4"),
    "first_name": "Sammy",
    "last_name": "Shark",
    "emails": [
        {
            "email": "[email protected]",
            "type": "work"
        },
        {
            "email": "[email protected]",
            "type": "home"
        }
    ],
    "courses": [
        ObjectId("61741c9cbc9ec583c836170a"),
        ObjectId("61741c9cbc9ec583c836170b")
    ],
    "message_board_messages": [
        ObjectId("61741c9cbc9ec583c836174c"),
        . . .
    ]
}

이 예시에서 message_board_messages 필드는 이제 Sammy가 작성한 모든 메시지에 대한 자식 참조를 저장합니다. 그러나 이러한 접근 방식을 변경하면 이전에 언급된 문제 중 하나만 해결할 수 있습니다. 즉, 이제 메시지에 독립적으로 접근할 수 있게 되었습니다. 그러나 이 관계의 무제한적인 카디널리티로 인해 객체 식별자 모음도 다루기 힘들어질 수 있습니다. 학생이 학업을 마치기 전에 수천 개의 메시지를 쉽게 작성할 수 있기 때문입니다.

이러한 시나리오에서 한 객체를 다른 객체에 연결하는 일반적인 방법은 부모 참조를 통하는 것입니다. 이전에 설명한 자식 참조와 달리, 이제는 학생 문서가 개별 메시지를 참조하는 것이 아니라, 메시지 문서에 학생을 가리키는 참조가 있습니다.

부모 참조를 사용하려면 메시지 문서 스키마를 수정하여 메시지를 작성한 학생에 대한 참조를 포함해야 합니다:

{
    "_id": ObjectId("61741c9cbc9ec583c836174c"),
    "subject": "Books on kinematics and dynamics",
    "message": "Hello! Could you recommend a good introductory books covering the topics of kinematics and dynamics? Thanks!",
    "posted_on": ISODate("2021-07-23T16:03:21Z"),
    "posted_by": ObjectId("612d1e835ebee16872a109a4")
}

새로운 posted_by 필드에 학생 문서의 객체 식별자가 포함되어 있음을 확인하세요. 이제 학생 문서에는 자신이 게시한 메시지에 대한 정보가 포함되지 않습니다:

{
    "_id": ObjectId("612d1e835ebee16872a109a4"),
    "first_name": "Sammy",
    "last_name": "Shark",
    "emails": [
        {
            "email": "[email protected]",
            "type": "work"
        },
        {
            "email": "[email protected]",
            "type": "home"
        }
    ],
    "courses": [
        ObjectId("61741c9cbc9ec583c836170a"),
        ObjectId("61741c9cbc9ec583c836170b")
    ]
}

학생이 작성한 메시지 목록을 검색하려면 메시지 컬렉션에 대한 쿼리를 실행하고 posted_by 필드에 대해 필터링합니다. 메시지를 별도의 컬렉션에 보관하면 메시지 목록이 늘어나도 학생 문서에 영향을 주지 않는 것이 안전합니다.

참고: 부모 참조를 사용할 때, 부모 문서를 참조하는 필드에 인덱스를 생성하면 부모 문서 식별자에 대한 필터링을 할 때마다 쿼리 성능을 크게 향상시킬 수 있습니다.

관련 문서의 양이 무제한인 일대다 관계를 모델링할 때, 문서가 독립적으로 액세스되어야 하는지 여부에 관계없이, 관련 문서를 별도로 저장하고 부모 참조를 사용하여 부모 문서에 연결하는 것이 일반적으로 권장됩니다.

결론

문서 지향 데이터베이스의 유연성 덕분에 문서 데이터베이스에서 관계를 모델링하는 최선의 방법을 결정하는 것은 관계형 데이터베이스에서처럼 엄격한 과학보다는 덜 엄격한 과학입니다. 이 글을 통해 문서를 내장하고 자식 및 부모 참조를 사용하여 관련 데이터를 저장하는 방법에 대해 알게 되었습니다. 관계 카디널리티를 고려하고 무제한 배열을 피하며, 문서가 별도로 또는 빈번하게 액세스될지 여부를 고려하는 방법에 대해 배웠습니다.

이것들은 MongoDB에서 일반적인 관계를 모델링하는 데 도움이 되는 몇 가지 지침일 뿐이지만, 데이터베이스 스키마 모델링은 일괄적으로 적용되는 것이 아닙니다. 항상 애플리케이션과 데이터를 사용하고 업데이트하는 방법을 고려하여 스키마를 설계하세요.

MongoDB에서 스키마 설계 및 다양한 종류의 데이터를 저장하기 위한 일반적인 패턴에 대해 더 알아보려면, 해당 주제에 대한 공식 MongoDB 문서를 확인하시기 바랍니다.

Source:
https://www.digitalocean.com/community/tutorials/how-to-design-a-document-schema-in-mongodb