[MongoDB] Schema 설계

유동균·2023년 2월 4일
0

MongoDB

목록 보기
12/12
post-thumbnail

1. Schema란?

  • MongoDB에서 Schema는 데이터베이스에서 사용되는 문서의 구조를 정의하는 것
  • Schema는 필드 이름, 타입, 기본값, 제약 조건 등을 정의하여 문서의 형식을 결정
  • MongoDB는 Schemaless이므로, 각 문서는 자유롭게 필드를 추가하거나 제거할 수 있다.
  • 각 문서의 구조를 일정하게 유지하고자 하는 경우에는 스키마를 사용할 수 있음
  • MongoDB에서 스키마를 사용하는 방법은 여러가지가 있지만, 가장 일반적인 방법으로는 Mongoose(Node.js)를 사용하는 것이다.
  • Mongoose는 MongoDB와 Node.js 사이의 Object Document Mapping(ODM) 라이브러리로, MongoDB 데이터베이스에서 데이터를 조작할 때 스키마를 적용할 수 있는 기능을 제공한다.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const contactSchema = new Schema({
  name: { type: String, required: true },
  email: { type: String, required: true },
  phone: { type: String, required: true, unique: true },
});
const Contact = mongoose.model('Contact', contactSchema);
module.exports = Contact;
  • 위의 예제는 Mongoose를 사용하여 주소록의 연락처를 나타내는 Contact 모델을 정의하는 것이다.
  • contactSchema에서는 이름, 이메일, 전화번호 필드가 필수적으로 포함되어야 하며, 전화번호 필드는 유일해야 함을 정의한다.

2. Schema Design

MongoDB에서, 엔티티는 데이터베이스에 저장된 개체, 즉 문서를 나타내는 것이다. 이 문서는 특정 속성과 값을 갖고 있으며, 데이터베이스 컬렉션의 멤버이기도 하다.

데이터베이스 컬렉션에서 멤버는 그 컬렉션 내의 개별 문서를 의미한다. 각 문서는 엔티티의 개별 인스턴스를 나타내며, 컬렉션 내의 모든 문서는 그 컬렉션의 멤버를 구성한다.

Instance는 객체지향 프로그래밍에서 클래스의 실제 예시, 특정 개체, 구체적인 객체를 의미한다. 클래스의 정의를 따르는 어떤 개체를 말한다. 예를 들어, 개발자가 정의한 "Person" 클래스의 인스턴스는 "John", "Jane" 등의 개인이 될 수 있다.

2.1 데이터의 관계 타입

2.1.1 One-to-One 관계

MongoDB에서 One-to-One 관계는 두 개의 엔티티 사이의 관계를 나타내는 것으로, 각 엔티티는 하나의 연관된 엔티티만을 가질 수 있다는 것을 뜻한다. 다른 말로, 한 컬렉션에 있는 한 개의 문서는 다른 컬렉션에 있는 한 개의 문서와만 관련될 수 있다는 것이다.

  • 예를 들어, "User" 컬렉션과 "Address" 컬렉션 간의 One-to-One 관계를 보여주는 자바스크립트의 예시는 다음과 같다.
  • 각 사용자는 하나의 주소만을 가질 수 있다는 것을 나타낸다.
// User Collection
{
  "_id": ObjectId("5f3e6..."),
  "name": "John Doe",
  "email": "johndoe@example.com",
  "address_id": ObjectId("5f3e7...")
}

// Address Collection
{
  "_id": ObjectId("5f3e7..."),
  "street": "123 Main St",
  "city": "San Francisco",
  "state": "CA",
  "zip": "94111"
}
  • 예제에서, "User" 컬렉션의 "address_id" 필드는 "Address" 컬렉션의 "_id" 필드에 참조하여, 두 컬렉션 간의 One-to-One 관계를 형성한다.

2.1.2 One-to-Many 관계

MongoDB에서 One-to-Many 관계란, 한 개의 문서가 다른 컬렉션의 여러 문서와 관계를 갖는 것을 의미한다.
즉, 한 컬렉션의 한 개의 문서가 다른 컬렉션의 여러 개의 문서와 관계를 갖는 것을 말한다.

  • 아래는 "user" collection과 "posts" collection 간에 One-to-Many 관계를 보여주는 자바스크립트 코드이다.
const User = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  email: {
    type: String,
    required: true,
    unique: true
  },
  posts: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Post'
  }]
});

const Post = new mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  body: {
    type: String,
    required: true
  },
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User'
  }
});
  • "User" 컬렉션과 "Post" 컬렉션은 관계를 형성하고 있다.
  • 각 사용자는 여러 게시물을 작성할 수 있으며, 게시물은 하나의 작성자만 가질 수 있습니다.
  • 이는 "author_id" 필드가 "User" 컬렉션의 "_id" 필드와 연결되어 있어, "Post" 컬렉션의 각 문서는 "User" 컬렉션의 하나의 문서와 연결되어 있다는 것을 나타낸다.

2.1.3 Many-to-Many 관계

MongoDB에서의 Many-to-Many 관계란, 각 엔티티가 여러 개의 연관 엔티티를 가질 수 있는 관계를 의미한다. 다른 말로 하자면, 한 컬렉션의 문서는 다른 컬렉션의 여러 문서와 관련이 있을 수 있고, 반대도 마찬가지이다.

  • 아래의 예시는 "Student" 컬렉션과 "Course" 컬렉션 간의 Many-to-Many 관계를 보여준다. 각 학생은 여러 개의 과정에 등록할 수 있으며, 각 과정도 여러 학생을 가질 수 있다.
// "Student" collection document 
{
  "_id": ObjectId("5f56fde9ccb3f6d1e2fec70a"),
    "name": "John Doe",
      "enrollments": [
        ObjectId("5f56fde9ccb3f6d1e2fec70b"),
        ObjectId("5f56fde9ccb3f6d1e2fec70c")
      ]
}

// "Course" collection document 
{
  "_id": ObjectId("5f56fde9ccb3f6d1e2fec70b"),
    "name": "Computer Science 101",
      "students": [
        ObjectId("5f56fde9ccb3f6d1e2fec70a"),
        ObjectId("5f56fde9ccb3f6d1e2fec70d")
      ]
}
  • 이 예제에서 "Student" 컬렉션의 "enrollments" 필드와 "Course" 컬렉션의 "students" 필드는 각 컬렉션에서 관련 문서의 "_id" 필드를 참조하여, 두 컬렉션 간의 Many-to-Many 관계를 설정한다.

2.2 데이터의 관계 타입을 구현하는 방법

데이터베이스에서 데이터 간의 연결 관계를 정의하고 구현하는 것을 말한다.
데이터의 정제와 정규화, 효율적인 데이터 관리를 위해 필요하다.
어떤 방식을 사용할지는 데이터의 종류, 용도, 사용자의 필요에 따라 결정되어야 한다.

2.2.1 관계 모델링 방식을 사용할때 고려해야 할 요소

  1. 데이터 접근 패턴: 관련 문서의 데이터를 자주 접근해야 할 경우, Embedded 관계 모델링 방식을 사용하는 것이 효율적일 수 있다.

    반대로, 관련 문서를 별도로 업데이트해야 할 경우 Referenced 관계 모델링 방식을 고려해야 할 수 있다.

  2. 데이터 크기: 관련 문서가 작은 경우, 이들을 Embedded 문서로 저장하는 것이 편리하다.

    관련 문서가 큰 경우, 이들을 별도의 문서로 저장하고 Referenced 관계를 사용하여 이들을 연결하는 것이 더 좋다.

  3. 일관성: Embedded 관계 모델링은 단일 문서 내에서 트랜잭션 일관성을 유지할 수 있지만, Referenced 관계 모델링은 수동적인 일관성 관리가 필요하다.

  4. 성능: Embedded 관계를 사용한 쿼리는 보통 빠르지만, 문서 크기가 커지면 느려질 수 있다. Referenced 관계는 쿼리에서 느릴 수 있지만, 문서 크기가 커지도 성능이 저하되지 않는다.

2.2.2 Embedded

관계가 있는 두 문서를 하나의 문서에 임베딩하여 관계를 표현하는 방식
Embedded는 관계가 있는 두 문서의 데이터를 하나의 문서에 저장하여 관계를 표현

{
   _id: ObjectId("5f60a2c6401ca095f5befa5a"),
   name: "John Doe",
   address: {
      street: "123 Main St",
      city: "San Francisco",
      state: "CA",
      zip: 94109
   },
   email: "john.doe@example.com"
}
  • 관련된 데이터를 하나의 문서에 모두 포함시켜 저장하는 방식이다.
    위의 예시에서 "John Doe" 사용자의 주소 정보는 "John Doe" 문서 안에 포함되어 저장되고 있다.

  • Embedded 데이터 구조는 다음과 같은 데이터에 적합하다.

    • 관계가 약한 데이터
    • 언제든지 검색하거나 조회해야 하는 것이 아니라면
    • 데이터 사이즈가 작은 경우
  • Embedded Documents 방식의 장점:

    • 데이터가 같은 문서 안에 모두 포함되어 있어 조회 속도가 빠름. (데이터를 조회할 때 효율적입니다.)
    • 데이터의 정합성이 보장됨. (데이터의 연관성이 높을 때 사용하면 좋습니다.)
  • Embedded Documents 방식의 단점:

    • 문서의 크기 제한이 있음. (데이터의 크기가 커질 경우 성능이 떨어질 수 있습니다.)
    • 데이터의 재사용성이 떨어짐. (자주 변경되는 데이터를 관리할 때 힘들어질 수 있습니다.)

2.2.3 Referenced

관련된 데이터를 다른 문서에 참조하는 방식(관계가 있는 두 문서의 ObjectID를 가지고 관계를 표현)
참조 문서에서 관계가 있는 문서의 ObjectID를 저장하여 관계를 표현할 수 있으며, 관련 문서에 대한 정보를 가지고 있는 문서를 참조할 수 있다.

// Embedded방식을 Referenced방식으로 변경
// user document
{
   _id: ObjectId("5f60a2c6401ca095f5befa5a"),
   name: "John Doe",
   address_id: ObjectId("5f60a2c6401ca095f5befa5b"),
   email: "john.doe@example.com"
}

// address document
{
   _id: ObjectId("5f60a2c6401ca095f5befa5b"),
   street: "123 Main St",
   city: "San Francisco",
   state: "CA",
   zip: 94109
}
  • 관련된 데이터를 분리하여 다른 문서에 저장하는 방식이다.

  • 위의 예시에서 "John Doe" 사용자의 주소 정보는 별도의 "Address" 문서에 저장되고 "John Doe" 문서에는 "Address" 문서의 ObjectId 값이 참조되고 있다.

  • Referenced 방식은 관계형 데이터베이스의 개념에 기반한 데이터 구조에 적합

    • 즉, 데이터가 중복되지 않고,
    • 각 데이터 간의 관계가 명확하게 표현되어야 할 때
  • Referenced Documents 방식의 장점:

    • 데이터의 크기가 커져도 성능에 문제가 없다.
    • 데이터의 재사용성이 높음.(자주 변경되는 데이터를 관리하기 쉽다.)
    • 데이터의 정합성이 보장됨.
  • Referenced Documents 방식의 단점:

    • 복잡한 조인 연산이 필요함.(데이터를 조회할 때 효율적이지 않다.)
    • 조회 속도가 느림.

2.3 MongoDB Schema Design의 기본 룰

정규화(normalization)-데이터베이스 구조를 최소한의 중복으로 만들어 데이터의 일관성과 안정성을 높이는 것을 목적.

  • 정규화의 장점:
    • 데이터 중복을 줄이고 불일치한 데이터를 제거한다.
    • 데이터의 정질과 정확성을 향상시킨다.
    • 데이터베이스의 확장성과 유지 관리성을 지원한다.
  • 정규화의 단점:
    • 데이터베이스 구조와 쿼리의 복잡성이 증가한다.
    • 여러 조인이 필요하여 쿼리 성능이 느려진다.
    • 데이터 삽입, 업데이트, 삭제가 어려워진다.

비정규화(denormalization)-정규화에서 제거된 데이터를 다시 테이블에 포함시켜 읽기 성능을 향상시키는 것을 목적.

  • 비정규화의 장점:
    • 조인의 수를 줄여 쿼리 성능을 향상시킨다.
    • 데이터 조회를 더욱 간단하고 효율적으로 만든다.
    • 데이터베이스 구조의 복잡성을 줄인다.
  • 비정규화의 단점:
    • 데이터 중복이 증가하고 불일치하는 데이터의 위험성이 증가한다.
    • 데이터 정확성과 일관성이 감소한다.
    • 데이터를 업데이트하고 유지하는 것이 더욱 어렵다.

따라서 정규화와 비정규화의 밸런스를 잘 잡아야 하며, 적절한 경우에는 정규화를, 읽기 성능이 중요한 경우에는 비정규화를 활용하는 것이 좋다.


2.3.1 읽기 성능을 향상시키기 위한 비정규화 데이터

  • MongoDB는 읽기에 최적화되어 있어 데이터를 비정규화하면 쿼리 성능이 향상된다.

2.3.2 관련 데이터를 함께 저장하기

  • 같은 문서나 embedded 문서에 관련 데이터를 저장하여 복잡한 조인을 피하기.

2.3.3 과도한 정규화 피하기

  • 데이터를 너무 정규화하면 복잡하고 느려지는 쿼리가 발생할 수 있으므로, 정규화와 비정규화 사이의 균형을 유지.

2.3.4 적절한 데이터 타입 사용하기

  • 각 필드에 적절한 데이터 타입을 선택하기. 예를 들어, 참조용으로는 ObjectId, 날짜용으로는 Date 등을 사용하여 최적의 성능과 기능을 보장하기.

2.3.5 성능 모니터링

  • 데이터베이스의 성능을 정기적으로 모니터링하고 효율성을 향상하기 위한 변경사항을 적용.

2.3.6 사용 사례 고려

  • 스키마를 설계할 때 애플리케이션의 특정 사용 사례와 요구 사항을 고려하고 필요에 맞는 모델링 방법을 선택하기.

0개의 댓글