MongoDB 데이터 모델링

Yuno·2021년 3월 18일
4
post-thumbnail

프로젝트 DB를 MongoDB로 결정하여, 데이터 모델링에 대해 학습합니다.
( 작성자 역시 입문자로써 문서를 참고하여 해석한대로 작성하였습니다 )

MongoDB 란?

  • NoSQL 데이터베이스
  • Doucmnet 지향 데이터베이스

NoSQL
SQL 계열 쿼리 언어를 사용할 수 있다는 사실을 강조하며 "Not-Only SQL" 또는,
전통적인 관계형 DB(RDB) 보다 덜 제한적이라는 "Non-Relational Operational SQL" 로 불리는데,

보통, "Not-Only SQL"로 불립니다.

Document
RDB의 행보다 유연한 모델인 Document를 지향합니다.
RDB와 다르게 고정된 스키마가 아닌, 동적 스키마입니다.
따라서, 하나의 컬렉션 안의 Document들은 다른 스키마를 가질 수 있습니다.

MongoDB는 통신 규격으로 JSON을 사용합니다. 한개 이상의 Key-Value 쌍으로 이루어집니다.

//user
{
	_id : "hanganda23",
  	name : "yuno",
}

관계 데이터 저장 방법

관계 데이터를 저장하는 유형 2가지

  • Embedded
  • Reference

Embedded

두 종류의 Document의 관계에서, 하나의 Document 데이터를 다른 Documnet에 포함시키는 방법입니다.

//User
{
	_id : "hanganda",
  	name : "yuno",
  	address : {
            street : "Banpo dae-ro",
            city : "Seoul",
            zip : "111111",
    	},
}

user.address에 Address Documnet가 통째로 저장됩니다.

Reference

Document를 통째로 저장하는 것이 아닌, 참조할 수 있도록 id를 저장합니다.
(관계형 DB와 유사)

//movie
{
     "_id" :  1 , 
     "title" :  "The Arrival of a Train" , 
     "year" :  1896 , 
}

//movie_detail
{
    "_id" :  156 , 
  
    "movie_id" :  1 ,  // movie Colletion 참조 (*) 
  
    " plot " :  "한 무리의 사람들이 기차역에서... " ,
    "fullplot" : "한 무리의 사람들이 기차역에서 플랫폼을 따라 다가오는 기차를 기다리고 있습니다."
    "type": "movie",
    "directors": [ "Auguste Lumière", "Louis Lumière" ],
    "imdb": {
      "rating": 7.3,
      "votes": 5043,
      "id": 12
    },
    "countries": [ "France" ],
    "genres": [ "Documentary", "Short" ],
}

(*) : movie_id 항목이 movie 컬렉션을 참조하고 있습니다.


관계 유형

  • One-To-One
  • One-To-Many
  • Many-To-Many

각 관계와 상황에 따라 어떤 저장 방식이 유리한지 판단하고, 어떻게 하는지 학습합니다.

One-To-One

유저와 주소를 1:1 매핑하는 예시에서, embedded가 reference보다 이점이 있습니다.

주소 정보가 자주 요청될 때,
embedded은 한번의 요청으로 유저의 정보 전체를 검색할 수 있습니다.

하지만, reference은 추가적인 요청을 통해야만 가져올 수 있습니다.

단점

하지만, Embedded pattern 은
불필요한 필드를 포함한 큰 문서가 될 수 있다는 잠재적인 문제를 가지고 있습니다.
이러한 불필요한 데이터는 성능 저하를 일으킵니다.

위 쪽의 예시 Movie, MovieDetail이 하나의 컬렉션으로 표현 되었다고 생각해봅시다.
간단한 개요를 표시할 때는, 필요하지 않는 몇몇 필드를 포함하고 있습니다.

해결

이럴 때는, 두 개의 컬렉션으로 분할하고, 참조합니다.

자주 로드하는 정보를 Movie 컬렉션에,
영화의 세부 데이터와 같은 적게 검색 되는 데이터 정보를 Movie_detail 컬렉션에 분할하고 참조합니다.

자주 액세스하는 데이터만 포함시킨 작은 문서를 사용하여, 데이터의 읽기 성능을 향상시킵니다.

One-To-Many

user의 address가 2개 이상이며, address 정보가 user와 함께 자주 검색되는 경우

Embedded는 마찬가지로 하나의 쿼리로 검색할 수 있습니다.

{
   "_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"
                }
              ]
 }

단점

역시, 필드가 제한되지 않는 경우 너무 큰 Document로 이어질 수 있습니다.

쇼핑몰을 예로,
제품에 대한 리뷰가 제한 없이 작성되어, 하나의 제품 Document가 너무 커지게 됩니다.

이럴 때는, 프로그램에 필요한 데이터만 포함할 수 있습니다.

사용자가 제품 페이지에 방문하면 어플리케이션은 10개의 가장 최근 리뷰를 로드한다고 합니다.
자주 사용되는 10개의 최근 리뷰와, 전체 리뷰 두 개의 컬렉션으로 분할합니다.

//product
{
  "_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")
    }
   	//최근 10개만 포함
  ]
}


//review
//리뷰 전체
{
  "review_id": 786,
  "product_id": 1, // product._id
  "review_author": "Kristina",
  "review_text": "This is indeed an amazing widget.",
  "published_date": ISODate("2019-02-18")
}
{
  "review_id": 785,
  "product_id": 1, // product._id
  "review_author": "Trina",
  "review_text": "Nice product. Slow shipping.",
  "published_date": ISODate("2019-02-17")
}

자주 사용되는 데이터를 하나의 쿼리로 검색하면서, Document가 제한 없이 커지는 것을 방지합니다.

추가로, 책과 작성자의 관계를 모델링 할 때,
Embeddeding 했다면 책에 작성자 정보가 반복되게 됩니다.

//book
{ 
   title :  "MongoDB : The Definitive Guide" , 
   저자 :  [  "Kristina Chodorow" ,  "Mike Dirolf"  ], 
   published_date :  ISODate ( "2010-09-24" ), 
   페이지 :  216 , 
   언어 :  "English" ,
   게시자 :  {
              이름 :  "O'Reilly Media" ,
              설립 :  1980 ,
              위치 :  "CA"
            }
}

{ 
   title :  "MongoDB 개발자를위한 50 가지 팁과 요령" , 
   저자 :  "Kristina Chodorow" , 
   published_date :  ISODate ( "2011-05-06" ), 
   페이지 :  68 , 
   언어 :  "English" ,
   게시자 :  {
              이름 :  "O'Reilly Media" ,
              설립 :  1980 ,
              위치 :  "CA"
            }
}

이러한 반복 문제를 가질 때, 작성자를 책 컬렉션과 별도의 컬렉션에 저장합니다.
다만, 참조할 때 관계가 증가함에 따라 참조를 저장할 위치가 달라집니다.

작성자 한 명당, 도서 수가 제한적이라면
작성자 Document에 도서 참조를 저장하는 것이 유용할 수 있습니다.

{
   name: "O'Reilly Media",
   founded: 1980,
   location: "CA",
   books: [123456789, 234567890, ...] // (*)
}

하지만, 배열이 가변적이고 증가합니다.
이를 방지하려면 book 컬렉션에 작성자 참조를 저장합니다.

{
   _id: 123456789,
   title: "MongoDB: The Definitive Guide",
   author: [ "Kristina Chodorow", "Mike Dirolf" ],
   published_date: ISODate("2010-09-24"),
   pages: 216,
   language: "English",
   publisher_id: "oreilly" // (*)
}

{
   _id: 234567890,
   title: "50 Tips and Tricks for MongoDB Developer",
   author: "Kristina Chodorow",
   published_date: ISODate("2011-05-06"),
   pages: 68,
   language: "English",
   publisher_id: "oreilly" // (*)
}

Many-To-Many

책 한권당, 작성자가 여러 명이 될 수 있습니다.
그 작성자 역시 여러 책을 작성했을 수 있습니다.

이 역시, 참조하는 관계의 증가에 따라 참조를 저장할 위치를 지정합니다.
책 한권당, 작성자의 수가 비교적 제한적이므로, 책에서 작성자를 참조합니다.

참고

https://docs.mongodb.com/manual/applications/data-models-relationships/

profile
web frontend developer

0개의 댓글