[NoSQL 데이터모델] MongoDB - 데이터 모델

MongoDB - 데이터 모델

https://docs.mongodb.com/manual/core/data-modeling-introduction/

 

 

​*** 데이터 모델링 소개 *** 

 

​MongoDB에서의 데이터는 유연한 스키마를 가진다. 데이터를 삽입하기 전에 테이블 스키마를 결정하고 선언해야 하는 SQL 데이터베이스와는 달리, MongoDB의 콜렉션은 도큐먼트 구조를 강제하지 않는다. 이런 유연함은 도큐먼트를 객체로 매핑함을 용이하게 해준다. 각 도큐먼트는 비록 데이터가 상당한 변동을 가진다고 하더라도 대표되는 객체의 데이터 필드를 매칭할 수 있다. 하지만 실제로는 한 콜렉션 안의 도큐먼트들은 비슷한 구조를 공유한다.

 

데이터 모델링에 있어서의 주요 과제는 애플리케이션의 요구와 데이터베이스 엔진의 성능 특징, 그리고 데이터 양도 패턴들을 균형잡는 것이다. 데이터 모델을 디자인할 때, 항상 데이터의 애플리케이션 사용 뿐만 아니라 데이터 자체의 선천적인 구조도 고려해야 한다.

 

도큐먼트 구조

​MongoDB 애플리케이션을 위한 데이터 모델을 디자인하는데 있어서의 주요 결정사항은 도큐먼트의 구조와 애플리케이션이 데이터 사이의 관계를 어떻게 표현하느냐를 중심으로 돌아간다. 애플리케이션이 이들 관계성을 표현하게 해주는 2개의 툴이 있다. 참조(reference)와 내장 도큐먼트(embedded document).

 

​참조 (Reference) 

​참조는 하나의 도큐먼트로부터 다른 것으로의 연결 혹은 참조를 포함함으로써 데이터 사이의 관계성을 저장한다. 애플리케이션은 이들 참조를 해결하여 관련된 데이터에 접근할 수 있다. 넓게 보자면, 이것은 정규화된 데이터 모델이다.

 

내장 데이터 (Embedded Data)

​내장 도큐먼트는 관련된 데이터를 단일 도큐먼트 구조 안에 저장함으로써 데이터 사이의 관련성을 가지게 한다. MongoDB 도큐먼트는 도큐먼트 구조를 한 도큐먼트 내의 필드 혹은 배열안에 내장시킴으로써 이것을 가능하게 한다. 이런 역정규화된 데이터 모델은 애플리케이션이 단일 데이터베이스 연산으로 관련된 데이터를 양도하고 조작할 수 있게 해준다.

 

쓰기 연산의 원자성

​MongoDB에서 쓰기 연산은 도큐먼트 수준에서 원자적이고, 단일 쓰기 연산이 하나 이상의 도큐먼트 혹은 하나 이상의 콜렉션에 원자적으로 영향을 줄 수 없다. 내장된 데이터를 가지는 역정규화된 데이터 모델은 대표되는 개체를 위한 모든 관련된 데이터를 단일 도큐먼트로 묶는다. 이것은 단일 쓰기 연산이 하나의 개체를 위해 데이터를 삽입 혹은 변경할 수 있기 때문에 원자적 쓰기 연산을 용이하게 해준다. 데이터 정규화는 데이터를 여러 콜렉션으로 분리하고 원자적이지 않은 여러 쓰기 연산을 요구하게 된다.

 

하지만, 원자적 쓰기를 용이하게 하는 스키마는 애플리케이션이 데이터를 사용하는 방법을 제한하거나 애플리케이션을 변경하는 방법을 제한할지도 모른다. 

 

도큐먼트 성장

​요소를 배열을 넣거나 새로운 필드를 추가하는 것과 같은 몇몇 업데이트는 도큐먼트의 크기를 증가시킨다.

 

MMAPv1 저장소 엔진에서는, 만약 도큐먼트 크기가 그 도큐먼트를 위해 할당된 공간을 초과하게 되면, MongoDB는 그 도큐먼트를 디스크에 재할당한다. MMAPv1 저장소 엔진을 사용할 때, 성장 고려나 데이터를 정규화할지 역정규화할지를 결정하는데 영향을 줄 수 있다. 

 

데이터 사용과 성능

​데이터 모델을 디자인할 때, 애플리케이션이 여러분의 데이터베이스를 어떻게 사용할 지를 고려하라. 예를 들어, 만약 여러분의 애플리케이션이 오직 최근에 삽입된 도큐먼트들만 사용한다면, capped collection 사용을 고려하라. 혹은 만약 여러분의 애플리케이션 요구가 주로 콜렉션에 대한 읽기 연산이라면, 일반적인 쿼리 지원을 위한 인덱스 추가가 성능을 개선할 수 있다.

 

추가적 리소스

 

 

*** 스키마 유효성 ***

 

​MongoDB는 업데이트와 삽입 동안 스키마 유효성을 수행할 수 있는 능력을 제공한다.

 

​유효성 규칙을 명시하기 

​유효성 규칙은 콜렉션 단위로 동작한다.

 

새로운 콜렉션을 생성할 때 유효성 규칙을 명시하려면, db.createCollection()에 validator 옵션을 사용하라.

 

이미 존재하는 콜렉션에 도큐먼트 유효성을 추가하려면, collMod 명령에 validator 옵션을 사용하라.

 

MongoDB는 또한 다음과 같이 관련된 옵션들을 제공한다.

  • validationLevel 옵션. 이것은 업데이트 동안에 MongoDB가 이미 존재하는 도큐먼트에 유효성 규칙을 얼마나 엄격하게 적용시킬지를 결정한다.
  • validationAction 옵션. 이것은 유효성 규칙을 위반한 도큐먼트를 거절하는 error를 행할지 아니면 위반을 로그에 남기고 무효한 도큐먼트를 허용하는 warn을 행할지를 결정한다.
 

JSON 스키마

​MongoDB은 3.6부터 JSON 스키마 유효성을 지원한다. JSON 스키마 유효성을 명시하려면, validator 표현식에 $jsonSchema 연산자를 사용하라.

 

JSON 스키마는 스키마 유효성을 수행하는 권장되는 수단이다.

 

예를 들어, 다음 예제는 JSON 스키마를 사용하여 유효성 규칙을 명시한다.

db.createCollection("students", {

   validator: {

      $jsonSchema: {

         bsonType: "object",

         required: [ "name", "year", "major", "gpa" ],

         properties: {

            name: {

               bsonType: "string",

               description: "must be a string and is required"

            },

            gender: {

               bsonType: "string",

               description: "must be a string and is not required"

            },

            year: {

               bsonType: "int",

               minimum: 2017,

               maximum: 3017,

               exclusiveMaximum: false,

               description: "must be an integer in [ 2017, 3017 ] and is required"

            },

            major: {

               enum: [ "Math", "English", "Computer Science", "History", null ],

               description: "can only be one of the enum values and is required"

            },

            gpa: {

               bsonType: [ "double" ],

               minimum: 0,

               description: "must be a double and is required"

            }

         }

      }

   }

})

 

쿼리 표현식

​MongoDB는 쿼리 연산자를 사용하여 쿼리 필터 표현식으로 유효성을 지원하는데, $near, $nearSphere, $text, $where 들은 예외이다.

 

예를 들어, 다음 예제는 쿼리 표현식을 사용하여 유효성 규칙을 명시한다.

db.createCollection( "contacts",

   { validator: { $or:

      [

         { phone: { $type: "string" } },

         { email: { $regex: /@mongodb\.com$/ } },

         { status: { $in: [ "Unknown", "Incomplete" ] } }

      ]

   }

} )

 

동작

​유효성은 업데이트와 삽입 동안에 발생한다. 여러분이 콜렉션에 유효성을 추가할 때, 이미 존재하는 도큐먼트들은 변경 때까지는 유효성 검사를 받지 않는다.

 

​이미 존재하는 도큐먼트 

​validationLevel 옵션은 MongoDB가 유효성 규칙을 어떤 연산에 적용할지를 결정한다.

  • validationLevel이 strict(기본)이면, MongoDB는 유효성 규칙을 모든 삽입과 업데이트에 적용한다.
  • validationLevel이 moderate이면, MongoDB는 유효성 규칙을 삽입과 이미 유효성 규칙을 수행한 이미 존재하는 도큐먼트에 대한 업데이트에 적용한다. moderate 수준으로, 유효성 규칙을 수행하지 않은 이미 존재하는 도큐먼트에 대한 업데이트는 유효성이 검사되지 않는다.
 
예를 들어, 다음 도큐먼트를 가지는 contacts 콜렉션을 생성하자.
 

db.contacts.insert([

   { "_id": 1, "name": "Anne", "phone": "+1 555 123 456", "city": "London", "status": "Complete" },

   { "_id": 2, "name": "Ivan", "city": "Vancouver" }

])

 
다음 명령을 실행하여 contacts 콜렉션에 유효성을 추가한다.
 

db.runCommand( {

   collMod: "contacts",

   validator: { $jsonSchema: {

      bsonType: "object",

      required: [ "phone", "name" ],

      properties: {

         phone: {

            bsonType: "string",

            description: "must be a string and is required"

         },

         name: {

            bsonType: "string",

            description: "must be a string and is required"

         }

      }

   } },

   validationLevel: "moderate"

} )

 
contacts 콜렉션은 이제 moderate 수준을 가지는 유효성을 가진다.
  • 만약 여러분이 1값의 _id를 가지는 도큐먼트를 업데이트 하려 한다면, MongoDB는 이미 존재하는 도큐먼트가 조건을 만족하기 때문에 유효성 규칙을 적용할 것이다.
  • 반대로, MongoDB는 2값의 _id를 가지는 도큐먼트 업데이트에는 유효성 규칙을 적용하지 않는데, 이는 유효성 규칙을 충족하지 않기 때문이다.
 
유효성을 전부 사용하지 않으려면, validationLevel을 off로 설정한다.

 

무효한 도큐먼트를 받기 혹은 거절하기

​validatioinAction 옵션은 MongoDB가 유효성 규칙을 위반한 도큐먼트를 어떻게 처리할 지를 결정한다.

  • validationAction이 error(기본)이면, MongoDB는 유효성 조건을 위반한 모든 삽입과 업데이트를 거절한다.
  • validationAction이 warn이면, MongoDB는 모든 위반을 로깅하고 삽입 혹은 업데이트를 허용한다.
 

제약 사항

​여러분은 admin, local, 그리고 config 데이터베이스 안의 콜렉션에 대해서 유효성을 명시할 수 없다.

 

여러분은 system.* 콜렉션에 대해서 유효성을 명시할 수 없다.

 

도큐먼트 유효성을 건너띄기

​사용자는 bypassDocumentValidation 옵션을 사용하여 도큐먼트 유효성을 건너띌 수 있다. 

 

추가 정보들

 

 

*** 데이터 모델링 개념 ***

 

데이터 모델 디자인

 

​효과적인 데이터 모델은 여러분 애플리케이션의 요구를 지원한다. 여러분의 도큐먼트 구조의 주요 고려사항은 내장이냐 아니면 참조 사용이냐를 결정하는 것이다.

 

내장 데이터 모델 (Embedded Data Model)

​MongoDB로, 여러분은 단일 구조 혹은 도큐먼트 안에 관련된 데이터를 내장시킬 수 있다. 이런 스키마는 보통 "역정규화된" 모델로 알려져 있는데, MongoDB의 풍부한 도큐먼트의 이점을 취한다. 

 

 {

     _id: <ObjectId1>,

     username: "123xyz",

     contact: {                                            -+

                   phone: "123-456-7890",              |

                   email: "xyz@example.com"            +--  내장 도큐먼트

               },                                           -+

     access: {                                            -+

                   level: 5,                                 +-- 내장 도큐먼트

                   group: "dev"                            |

               }                                            -+

 }

 

내장 데이터 모델은 애플리케이션이 관련된 정보 조각들을 같은 데이터베이스 레코드에 저장할 수 있도록 해준다. 결과적으로, 애플리케이션은 더 적은 쿼리와 업데이트를 발행하여 보통의 연산들을 완료할 수 있다.

 

일반적으로, 다음의 경우에 내장 데이터 모델을 사용하라.

  • 개체 사이에 관계성을 "포함"하고 있을 때. 
  • 개체 사이에 일대다 관계성을 가질 때. 이 관계성에서, 다측 혹은 자식 도큐먼트는 항상 일측 혹은 부모 도큐먼트의 문맥에서 나타나거나 보여진다.
 
보통 내장은 읽기 연산에서 더 좋은 성능을 제공하는데, 단일 데이터베이스 연산에서 관련된 데이터를 요청하고 양도하는 능력 또한 그렇다. 내장 데이터 모델은 단일 원자적 쓰기 연산에서 관련된 데이터를 업데이트하는 것을 가능하게 한다.
 
하지만, 도큐먼트 내의 내장 데이터는 도큐먼트가 생성 후에 성장하는 상황을 초래할 수 있다. MMAPv1 저장소 엔진에서, 도큐먼트 성장은 쓰기 성능에 악영향을 끼칠수 있으며 데이터 조각화를 유발시킬 수 있다.
 
버전 3.0.0부터, MongoDB는 도큐먼트 성장을 고려하기 위해 MMAPv1를 위한 기본 할당 전략으로서 2의 거듭제곱 할당을 사용하는데, 데이터 조각화 같은 것을 최소화시킨다. 
 
내장 도큐먼트와 상호작용 하려면, 내장 도큐먼트에 접근하기 위해 점 표기법을 사용하라.

 

정규 데이터 모델 (Normalized Data Model)

​정규 데이터 모델은 도큐먼트 사이에 참조를 사용하여 관계성을 서술한다.

 user 도큐먼트

 {

     _id: <ObjectId1>,

     username" "123xyz"

 }

 

 contact 도큐먼트

 {

     _id: <ObjectId2>, 

     user_id: <ObjectId1>,

     phone: "123-456-7890", 

     email: "xyz@example.com"

 }

 

 access 도큐먼트

 {

     _id: <ObjectId3>,

     user_id: <ObjectId1>,

     level: 5,

     group: "dev"

 }

 

일반적으로 다음의 경우에 정규 데이터 모델을 사용한다.

  • 내장이 데이터의 중복을 초래하고, 중복의 악영향으로 충분한 읽기 성능 이점을 제공하지 않을 때.
  • 복잡한 다대다 관계성을 표현하고자 할 때.
  • 큰 계층적 데이터 집합을 모델링하고자 할 때.
 
참조는 내장보다 더 유연함을 제공한다. 하지만 클라이언트 측 애플리케이션은 참조를 해결하기 위해 이어지는 쿼리를 발행해야만 한다. 즉, 정규 데이터 모델은 서버와의 더 많이 통신을 필요로 하게 된다.

 

추가적 리소스

 

 

운용적 인자와 데이터 모델

 

​MongoDB에서의 애플리케이션 데이터 모델링은 데이터 자체 뿐만 아니라 MongoDB 자체의 특성에도 영향을 받는다. 예를 들어, 애플리케이션은 서로 다른 데이터 모델로 좀더 효율적인 쿼리를 사용할 수 있고, 삽입과 업데이트 연산의 처리량을 증가시킬 수 있으며, 샤딩 클러스트의 활동을 좀더 효율적으로 분산시킬 수 있다.

 

이러한 인자들은 운용적이고 애플리케이션 외부의 요구사항들이지만 MongoDB에 기반한 애플리케이션의 성능에 영향을 준다. 데이터 모델을 개발할 때, 다음의 고려사항들에 맞춰 여러분 애플리케이션의 모든 읽기와 쓰기 연산을 분석하라.

 

도큐먼트 성장

​도큐먼트에 대한 몇몇 업데이트는 도큐먼트의 크기를 증가시킬 수 있다. 배열에 요소를 넣거나 도큐먼트에 새로운 필드를 추가하는 것들이 바로 이런 업데이트들이다.

 

MMAPv1 저장소 엔진을 사용할 때, 도큐먼트 성장은 여러분의 데이터 모델에 있어서 고려되어야 한다. MMAPv1에서, 도큐먼트 크기가 그 도큐먼트를 위해 할당된 공간을 초과한다면, MongoDB는 디스크상에 그 도큐먼트를 재할당시킨다. MongoDB 3.0.0부터는 2의 거듭제곱 할당이 이러한 재할당을 최소화시킬 뿐만 아니라 자유로워진 레코드 공간을 효율적으로 재사용하게 해준다.

 

MMAPv1을 사용할 때, 만약 여러분의 애플리케이션이 현재 2의 거듭제곱 할당을 초과하는 도큐먼트 성장을 빈번히 일으킨다면, 여러분은 여러분의 데이터 모델을 재조정하여 역정규화된 데이터 모델 보다는 구분된 도큐먼트 안의 데이터 사이에 참조를 사용하는 것이 낫다.

 

여러분은 또한 도큐먼트 성장을 피하기 위해 미리 할당 전략을 사용할 수도 있다.

 

원자성

​MongoDB에서, 연산은 도큐먼트 수준에서 원자적이다. 단일 쓰기 연산이 하나 이상의 도큐먼트를 변경할 수 없다. 콜렉션 내의 단일 도큐먼트 이상을 변경하는 연산은 여전히 한번에 하나의 도큐먼트에 대해 동작한다. 여러분의 애플리케이션이 같은 도큐먼트 내에서 모든 필드들을 원자적 의존성 요구로 저장하는지를 확인하라. 만약 애플리케이션이 2조각의 데이터로 비-원자적 업데이트를 허용한다면, 여러분은 이들 데이터를 분리된 도큐먼트로 저장할 수 있다.

 

연관된 데이터를 단일 도큐먼트 안에 내장하는 데이터 모델은 이와 같은 원자적 연산을 용이하게 해준다. 연관된 데이터 조각들 사이의 참조를 저장하는 데이터 모델에서, 애플리케이션은 분리된 읽기와 쓰기 연산을 발행하여 이들 연관된 데이터 조각들을 얻고 변경할 수 있다.

 

샤딩

​MongoDB는 수평적 확장성을 제공하기 위해 샤딩을 사용한다. 이런 클러스터는 규모가 큰 데이터 집합과 높은 처리량을 가지는 배치를 제공한다. 샤당은 많은 수의 mongod 인스턴스 혹은 샤드에 걸쳐 콜렉션의 도큐먼트들을 분산시키기 위해 사용자가 데이터베이스 내의 콜렉션을 나눌 수 있도록 해준다.

 

데이터와 애플리케이션 통신을 샤드 콜렉션으로 분산시키기 위해, MongoDB는 샤드키를 사용한다. 올바른 샤드키를 선택하는 것은 성능 향상에 중요하고, 쿼리 고립과 증가된 쓰기 용량에 중요하다. 샤드키로 사용되는 필드 혹은 필드들을 주의깊에 선택해야 한다.

 

인덱스

​일반적 쿼리의 성능 향상을 위해 인덱스를 사용하라. 쿼리에 자주 나타나는 필드와 정렬된 결과를 리턴하는 모든 연산을 위해 인덱스를 구축하라. MongoDB는 자동으로 _id 필드에 유일 인덱스를 생성한다.

 

여러분이 인덱스를 생성할 때, 다음과 같은 인덱스의 행동을 고려하라.

  • 각 인덱스는 최소한 8KB의 데이터 공간을 필요로 한다.
  • 인덱스 추가는 쓰기 연산에 있어서 몇몇 부정적인 성능 영향을 가진다. 높은 쓰기 대 읽기 비율을 가지는 콜렉션에서는, 삽입이 또한 모든 인덱스를 업데이트 해야 하기 때문에 인덱스는 비용이 많이 드는 것이 된다.
  • 높은 읽기 대 쓰기 비율을 가지는 콜렉션은 추가적인 인덱스로 종종 이점을 본다. 인덱스는 인덱스를 사용하지 않는 읽기 연산에 아무런 영향도 주지 않는다.
  • 활성화 될 때, 각 인덱스는 디스크 공간과 메모리를 소모한다. 이것은 상당할 수 있으며 가용성 계획를 위해 추적되어야 한다.
 

많은 수의 콜렉션

​어떤 상황에서는, 여러분은 단일 콜렉션보다는 여러 콜렉션 안에 관련된 정보를 저장하기를 선택할 지도 모른다.

 

다양한 환경과 애플리케이션을 위해 로그 도큐먼트를 저장하는 간단한 logs 콜렉션을 생각해보자.

{ log: "dev", ts: ..., info: ... }

{ log: "debug", ts: ..., info: ...}

 

만약 전체 도큐먼트의 수가 작다면, 여러분은 타입별 콜렉션으로 도큐먼트들을 그룹핑할 수도 있다. 로그에 대해서, logs_dev와 logs_debug와 같이 구분된 로그 콜렉션을 유지한다고 가정하자. logs_dev 콜렉션은 오직 개발 환경에 관련한 도큐먼트들만 포함될 것이다.

 

일반적으로, 많은 수의 콜렉션을 갖는 것은 눈의 띄는 성능 악화를 가지지 않고 매우 좋은 성능을 가져온다. 콜렉션을 구분하는 것은 높은 처리량의 배치 처리에 있어서 매우 중요하다.

 

많은 수의 콜렉션을 가지는 모델을 사용할 때, 다음과 같은 동작을 고려해야 한다.

  • 각 콜렉션은 몇 킬로바이트의 최소 오버헤드를 가진다.
  • _id상의 인덱스를 포함한 각 인덱스는 최소 8KB의 데이터 공간을 요구한다.
  • 각 데이터베이스에 대해, 단일 네임스페이스 파일(즉, <database>.ns)은 그 데이터베이스를 위한 모든 메타데이터를 저장하고, 각 인덱스와 콜렉션은 그 네임스페이스 파일에 자신만의 엔트리를 가진다. MongoDB는 네임스페이스 파일의 크기에 제한을 둔다.
  • mmapv1 저장소 엔진을 사용하는 MongoDB는 네임스페이스의 수에 제한을 가진다. 얼마나 많은 추가적인 네임스페이스가 허용되는지를 결정하기 위해 여러분은 현재 네임스페이스의 수를 알기 원할지도 모른다. 현재 네임스페이스의 수를 알려면, mongo shell에서 db.system.namespaces.count()를 사용하라. 네임스페이스 수의 제한은 <database>.ns 크기에 달려 있다. 네임스페이스 파일의 기본 크기는 16MB이다. 새로운 네임스페이스 파일의 크기를 변경하려면, 서버를 --nssize <new size MB> 옵션으로 시작하라. 이미 존재하는 데이터베이스에 대해서는, 서버를 --nnsize로 시작한 후, mongo shell에서 db.repairDatabase() 명령을 동작시켜라.
 

많은 수의 작은 도큐먼트들을 포함하는 콜렉션

만약 ​여러분이 많은 수의 작은 도큐먼트들을 가지는 콜렉션을 가진다면, 성능 이유로 내장을 고려해야 한다. 만약 여러분이 이런 작은 도큐먼트들을 몇몇 논리적 관계로 그룹핑 할 수 있고, 그리고 이런 그룹핑으로 도큐먼트들을 자주 얻는다면, 여러분은 이 작은 도큐먼트들을 내장 도큐먼트의 배열을 포함하는 큰 도큐먼트로 "돌돌 마는 것(rolling-up)"을 고려해야 할지도 모른다.

 

이들 작은 도큐먼트들을 논리적 그룹핑으로 "넣는 것(rolling-up)"은 이어지는 읽기를 포함하여 랜덤 디스크 엑세스를 줄이는 한 무리의 도큐먼트를 얻는 쿼리를 의미한다. 게다가, "넣어진(rolling-up)" 도큐먼트와 일반적인 필드를 더 큰 도큐먼트로 이동시키는 것은 이들 필드상의 인덱스에 이점이 생긴다. 일반적인 필드의 복사본이 적으며, 그리고 이에 상응하는 인덱스 안에 연관된 키 엔트리가 더 적어질 것이다.

 

하지만, 만약 여러분이 종종 그룹 내의 도큐먼트의 하위집합만을 얻는다면, "rolling-up" 도큐먼트는 더 좋은 성능을 제공하지 않을 수도 있다 .게다가, 만약 작고 분리된 도큐먼트가 그 데이터의 자연적 모델을 대표한다면, 여러분은 그 모델을 유지해야 한다.

 

작은 도큐먼트를 위한 저장소 최적화

​각 MongoDB 도큐먼트는 특정 양의 오버헤드를 포함한다. 이 오버헤드는 보통 무시할 만 하지만 만약 모든 도큐먼트가 오직 몇 바이트 뿐이라면 이는 눈에 띄게 되는데, 만약 도큐먼트가 오직 한둘의 필드만 가진다면 이는 기정 사실이 된다.

 

이들 콜렉션에 대해 다음과 같은 저장소 이용 최적화 제안과 전략을 고려하라.

  • _id 필드를 명시적으로 사용하라. MongoDB 클라이언트는 자동으로 각 도큐먼트에 _id 필드를 추가하고, _id 필드를 위한 12바이트 ObjectId를 생성한다. 게다가, MongoDB는 항상 _id 필드를 인덱싱한다. 작은 도큐먼트에서 이는 상당한 공간을 차지한다. 저장소 사용을 최적화하기 위해, 사용자는 콜렉션에 도큐먼트를 삽입할 때 명시적으로 _id 필드를 위한 값을 명시할 수 있다. 이 전략을 사용하면 애플리케이션은 _id 필드에 도큐먼트의 다른 부분의 공간을 점유할 값을 저장하도록 할 수 있다.
  • 짧은 필드명을 사용하라. MongoDB는 모든 도큐먼트에 모든 필드명을 저장한다. 대부분의 도큐먼트에서, 이것은 도큐먼트에 의해 사용되는 공간의 작은 부분을 차지한다. 하지만, 작은 도큐먼트에서, 필드명이 비율적으로 큰 부분을 차지할 수도 있다. 
  • 내장 도큐먼트. 몇몇 경우에, 여러분은 다른 도큐먼트 안에 내장 도큐먼트를 사용하여 도큐먼트당 오버헤드를 줄일 수 있다.

 

데이터 생명주기 관리

​데이터 모델링 결정은 데이터 생명주기 관리를 고려해야만 한다.

 

콜렉션의 Time to Live 혹은 TTL 특징은 특정 기간 이후 도큐먼트를 만료시킨다. 만약 에러분의 애플리케이션이 몇몇 데이터가 제한된 시간동안만 데이터베이스에 머물고자 한다면, TTL 특징을 사용하라.

 

추가적으로, 만약 여러분의 애플리케이션이 오직 최근에 삽입된 도큐먼트들만 사용한다면, capped collection를 고려하라. capped collection은 삽입된 도큐먼트의 FIFO 관리를 제공하고 삽입 순서에 근거한 도큐먼트 삽입과 읽기 연산을 효율적으로 지원한다.

 

 

*** 데이터 모델 예제와 패턴 ***

 

도큐먼트 사이의 관계성 모델링하기

 

내장 도큐먼트로 일대일 관계 모델링하기

​개관 

​MongoDB에서의 데이터는 유연한 스키마를 갖는다. 콜렉션은 도큐먼트 구조를 강제하지 않는다. 여러분은 어떻게 데이터를 모델링하는지에 영향을 주는 결정은 애플리케이션 성능과 데이터베이스 용량에 영향을 줄 수 있다. 

 

이 섹션은 연결된 데이터 사이의 관계성을 서술하기 위해 내장 도큐먼트를 사용하는 데이터 모델을 설명한다.

 

패턴

​후원자와 주소 관계를 매핑하는 예제를 살펴보자. 이번 예제는 만약 여러분이 한 데이터 관점에서 다른 데이터 개체를 볼 필요가 있다면 참조보다는 내장이 더 이점이 있음을 설명한다. patron와 address 데이터 사이의 일대일 관계에서, address는 patron에 속한다.

 

정규 데이터 모델에서, address 도큐먼트는 patron 도큐먼트에 대한 참조를 포함한다.

{

   _id: "joe",

   name: "Joe Bookreader"

}

 

{

   patron_id: "joe",

   street: "123 Fake Street",

   city: "Faketon",

   state: "MA",

   zip: "12345"

}

 

만약 address 데이터가 name 정보로 자주 얻어지게 된다면, 애플리케이션은 참조를 해결하기 위해 여러 쿼리를 발행해야 한다. 더 좋은 데이터 모델은 다음과 같이 address 데이러를 patron 데이터 안에 내장시키는 것이다.

{

   _id: "joe",

   name: "Joe Bookreader",

   address: {

              street: "123 Fake Street",

              city: "Faketon",

              state: "MA",

              zip: "12345"

            }

}

 

내장 데이터 모델로, 애플리케이션은 하나의 쿼리로 완전한 patron 정보를 얻을 수 있다.

 

내장 도큐먼트로 일대다 관계 모델링하기

패턴

​이번 patron과 address 데이터 사이의 일대다 관계에서, patron은 여러 address 개체를 갖는다.

 

정규 데이터 모델에서는, address 도큠너트가 patron 도큐먼트에 대한 참조를 포함한다.

{

   _id: "joe",

   name: "Joe Bookreader"

}

 

{

   patron_id: "joe",

   street: "123 Fake Street",

   city: "Faketon",

   state: "MA",

   zip: "12345"

}

 

{

   patron_id: "joe",

   street: "1 Some Other Street",

   city: "Boston",

   state: "MA",

   zip: "12345"

}

 

좀 더 최적화된 스키마는 다음과 같이 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"

                }

              ]

 }

 

도큐먼트 참조로 일대다 관계 모델링하기

​개관 

​이 섹션은 연결된 데이터 사이의 관계성을 서술하기 위해 도큐먼트 사이에 참조를 사용하는 데이터 모델을 설명한다.

 

패턴

​publisher와 book 관계를 매핑하는 다음 예제를 살펴보자.이 예제는 publisher 정보의 반복을 피하기 위해 내장을 넘어선 참조의 이점을 설명한다.

 

book 도큐먼트 안에 publisher 도큐먼트를 내장하는 것은 publisher 데이터의 반복을 초래하는데, 다음이 이를 보여준다.

{

   title: "MongoDB: The Definitive Guide",

   author: [ "Kristina Chodorow", "Mike Dirolf" ],

   published_date: ISODate("2010-09-24"),

   pages: 216,

   language: "English",

   publisher: {

              name: "O'Reilly Media",

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

              founded: 1980,

              location: "CA"

            }

}

 

{

   title: "50 Tips and Tricks for MongoDB Developer",

   author: "Kristina Chodorow",

   published_date: ISODate("2011-05-06"),

   pages: 68,

   language: "English",

   publisher: {

              name: "O'Reilly Media",

              founded: 1980,

              location: "CA"

            }

}

 

​publisher 데이터의 반복을 피하려면, 참조를 사용하여 publisher 정보를 book 콜렉션으로부터 분리된 콜렉션에 유지시킨다.

 

참조를 사용할 때, 관계성의 성장이 참조를 어디에 저장할 지를 결정한다. 만약 publisher당 book의 수가 제한된다면, publisher 도큐먼트 안에 book 참조를 저장하는 것은 때로 유용할 것이다. 반면에, publisher 당 book의 수가 제한이 없다면, 이 데이터 모델은 다음 예제와 같이 변화하고 자라는 배열을 초래한다.

{

   name: "O'Reilly Media",

   founded: 1980,

   location: "CA",

   books: [123456789, 234567890, ...]

}

 

{

    _id: 123456789,

    title: "MongoDB: The Definitive Guide",

    author: [ "Kristina Chodorow", "Mike Dirolf" ],

    published_date: ISODate("2010-09-24"),

    pages: 216,

    language: "English"

}

 

{

   _id: 234567890,

   title: "50 Tips and Tricks for MongoDB Developer",

   author: "Kristina Chodorow",

   published_date: ISODate("2011-05-06"),

   pages: 68,

   language: "English"

}

 

​변화하고 자라는 배열을 피하려면, book 도큐먼트 안에 publisher 참조를 저장한다.

{

   _id: "oreilly",

   name: "O'Reilly Media",

   founded: 1980,

   location: "CA"

}

 

{

   _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"

}

 

 

트리 구조 모델링하기

 

부모 참조로 트리 구조 모델링하기

​개관 

​이 섹션은 MongoDB 도큐먼트에서 부모 노드에 대한 참조를 자식 노드들 안에 저장하는 트리 같은 구조를 서술하는 데이터 모델을 설명한다.

 

패턴

​부모 참조(Parent Reference) 패턴은 도큐먼트 안에 각 트리 노드를 저장한다. 트리 노드에 추가로, 도큐먼트는 그 노드의 부모에 대한 id를 저장한다.

 

다음과 같은 카테고리의 계층도를 보자.

                                Books

                                   |

                            Programming

                                   |

                    -----------+-----------

                    |                              |

               Languages                   Databases

                                                   |

                                     ----------+-----------

                                     |                             |

                                MongoDB                        dbm

 

​다음 예제는 부모 참조를 사용하여 트리를 모델링하는데, 부모 카테고리에 대한 참조를 parent 필드에 저장한다.

db.categories.insert( { _id: "MongoDB", parent: "Databases" } )

db.categories.insert( { _id: "dbm", parent: "Databases" } )

db.categories.insert( { _id: "Databases", parent: "Programming" } )

db.categories.insert( { _id: "Languages", parent: "Programming" } )

db.categories.insert( { _id: "Programming", parent: "Books" } )

db.categories.insert( { _id: "Books", parent: null } )

  • ​노드의 부모를 얻는 쿼리는 빠르고 간단하다.

 db.categories.findOne( { _id: "MongoDB" } ).parent

  • 여러분은 부모 노드로의 검색을 빠르게 하기 위해 parent 필드에 인덱스를 생성할 수 있다.

 db.categories.createIndex( { parent: 1 } )

  • 여러분은 직계 자식 노드를 찾기 위해 parent 필드로 쿼리할 수 있다.

 db.categories.find( { parent: "Databases" } )

 
부모 연결(Parent Link) 패턴은 트리 저장에 간단한 해결책을 제공하지만 하위 트리를 얻는데 여러 쿼리를 필요로 한다.
 

자식 참조로 트리 구조 모델링하기

​개관 

​이 섹션은 MongoDB 도큐먼트에서 부모 노드들 안에 자식 노드들에 대한 참조를 저장하는 트리 비슷한 구조를 서술하는 데이터 모델을 설명한다.

 

패턴

​자식 참조(Child Reference) 패턴은 한 도큐먼트에 각 트리 노드들을 저장한다. 트리 노드에 더하여, 도큐먼트는 배열 안에 노드의 자식들의 id를 저장한다.

 

카테고리 계층도는 위 섹션의 그것과 동일하다.

 

다음 예제는 자식 참조를 사용하여 트리를 모델링하는데, 노드의 자식들에 대한 참조를 children 필드에 저장한다.

db.categories.insert( { _id: "MongoDB", children: [] } )

db.categories.insert( { _id: "dbm", children: [] } )

db.categories.insert( { _id: "Databases", children: [ "MongoDB", "dbm" ] } )

db.categories.insert( { _id: "Languages", children: [] } )

db.categories.insert( { _id: "Programming", children: [ "Databases", "Languages" ] } )

db.categories.insert( { _id: "Books", children: [ "Programming" ] } )

  • ​노드의 직계 자식들을 얻는 쿼리는 빠르고 간단하다.

 db.categories.findOne( { _id: "Databases" } ).children

  • 여러분은 자식노드로 빠른 검색을 하기 위해 children 필드에 인덱스를 생성할 수 있다.

 db.categories.createIndex( { children: 1 } )

  • 여러분은 어떤 노드의 부모 노드 뿐만 아니라 형제 노드들도 찾기 위해 children 필드로 검색할 수 있다.

 db.categories.find( { children: "MongoDB" } )

 
자식 참조 패턴은 하위 트리가 필요하지 않는 한 트리 저장에 적당한 해결책을 제공한다. 이 패턴은 또한 한 노드가 여러 부모들을 갖는 그래프를 저장하기 위한 적당한 해결책을 제공할 수도 있다.
 

선조 배열로 트리 구조 모델링하기

​개관 

​이 섹션은 MongoDB 도큐먼트에서 부모 노드에 대한 참조와 모든 선조를 저장하는 배열을 사용하는 트리 비슷한 구조를 서술하는 데이터 모델을 설명한다.

 

패턴

​선조 배열(Array of Ancestors) 패턴은 한 도큐먼트에 각 트리 노드를 저장한다. 트리 노드에 더하여, 도큐먼트는 배열 안에 노드의 선조의 id 또는 경로를 저장한다.

 

카테고리 계층도는 위 섹션과 동일하다.

 

다음 예제는 선조 배열을 사용하여 트리를 모델링한다. ancestors 필드 뿐만 아니라, 이들 도큐먼트는 또한 parent 필드에 직계 부모 카테고리에 대한 참조를 저장한다.

db.categories.insert( { _id: "MongoDB", ancestors: [ "Books", "Programming", "Databases" ], parent: "Databases" } )

db.categories.insert( { _id: "dbm", ancestors: [ "Books", "Programming", "Databases" ], parent: "Databases" } )

db.categories.insert( { _id: "Databases", ancestors: [ "Books", "Programming" ], parent: "Programming" } )

db.categories.insert( { _id: "Languages", ancestors: [ "Books", "Programming" ], parent: "Programming" } )

db.categories.insert( { _id: "Programming", ancestors: [ "Books" ], parent: "Books" } )

db.categories.insert( { _id: "Books", ancestors: [ ], parent: null } )

  • ​선조 또는 노드의 경로를 얻는 쿼리는 빠르고 간단하다.

 db.categories.findOne( { _id: "MongoDB" } ).ancestors

  • 여러분은 선조 노드로의 빠른 검색을 하기 위해 ancestors 필드에 인덱스를 생성할 수 있다.

 db.categories.createIndex( { ancestors: 1 } )

  • 여러분은 한 노드의 모든 후손들을 찾기 위해 ancestors 필드로 쿼리할 수 있다.

 db.categories.find( { ancestors: "Programming" } )

 
선조 배열 패턴은 ancestors 필드의 요소에 인덱스를 생성함으로써 후손들과 자기의 선조들을 찾는데 빠르고 효율적인 해결책을 제공한다. 선조 배열을 하위 트리로 작업할 때 이것은 좋은 선택이 된다.
 
선조 배열 패턴은 실체화 경로 패턴보다는 조금 느리지만 사용하기엔 좀더 직관적이다.

 

실체화 경로(materialized path)로 트리 구조 모델링하기

​개관 

​이 섹션은 MongoDB 도큐먼트에서 도큐먼트들 사이의 완전한 관계 경로를 저장하는 트리 같은 구조를 서술하는 데이터 모델을 설명한다.

 

패턴

​실체화 경로(Materialized Path) 패턴은 한 도큐먼트에 각 트리 노드를 저장한다. 트리 노드 뿐만 아니라, 도큐먼트는 노드의 선조들의 id 혹은 경로를 문자열로 저장한다. 비록 실체화 경로 패턴이 문자열과 정규 표현식으로 작업하는 추가 단계를 필요로 하지만, 이 패턴은 부분 경로로 노드를 찾는 것과 같은 경로로 작업하는 데 있어서 좀 더 유연함을 제공한다.

 

카테고리 계층도는 위 섹션과 동일하다.

 

다음 예제는 실체화 경로를 사용하는 트리를 모델링하는데, path 필드에 경로를 저장한다. 경로 문자열은 구분자로 콤마(,)를 사용한다.

db.categories.insert( { _id: "Books", path: null } )

db.categories.insert( { _id: "Programming", path: ",Books," } )

db.categories.insert( { _id: "Databases", path: ",Books,Programming," } )

db.categories.insert( { _id: "Languages", path: ",Books,Programming," } )

db.categories.insert( { _id: "MongoDB", path: ",Books,Programming,Databases," } )

db.categories.insert( { _id: "dbm", path: ",Books,Programming,Databases," } )

  • ​여러분은 전체 트리를 얻는 쿼리를 할 수 있는데, path 필드로 정렬한다.

 db.categories.find().sort( { path: 1 } )

  • 여러분은 Programming의 후손들을 찾기 위해 path 필드에 정규 표현식을 사용할 수 있다.

 db.categories.find( { path: /,Programming,/ } )

  • 여러분은 또한 Books가 계층도의 가장 상위 수준에 있는 Books의 후손들을 얻을 수 있다.

 db.categories.find( { path: /^,Books,/ } )

  • path 필드에 대한 인덱스를 생성하려면, 다음을 사용하라. 이 인덱스는 다음과 같은 쿼리에서의 성능을 개선할 것이다.
    • 루트 Books의 하위 트리(즉, /^,Books,/ 혹은 /^,Books,Programming,/)로부터의 쿼리에서, path 필드상의 인덱스는 쿼리 성능을 상당히 개선한다.
    • 루트로부터의 경로가 쿼리에 제공되지 않는 하위 트리나 혹은 노드가 인덱스된 문자열의 중간에 존재하는 하위 트리에 대한 쿼리에서, 그 쿼리는 전체 인덱스를 조사해야만 한다. 이들 쿼리에서, 인덱스는 만약 인덱스가 전체 콜렉션보다 훨씬 작다면 성능 향상을 제공할 수도 있다.

 db.categories.createIndex( { path: 1 } )

 

중첩셋(nested set)으로 트리 구조 모델링하기

​개관 

​이 섹션은 트리가 변할 수 있는 상황에서 하위트리를 찾는데 최적화된 트리 같은 구조를 서술하는 데이터 모델을 설명한다.

 

패턴

​중첩셋(Nested Set) 패턴은 트리 안의 각 노드를 트리 횡단에서의 각 중지점으로 구별한다. 애플리케이션은 트리 안의 각 노드를 두번 방문한다. 첫번째는 초기 여행시에, 그리고 두번째는 귀환 여행시이다. 중첩셋 패턴은 한 도큐먼트에 각 노드를 저장한다. 트리 노드에 더하여, 도큐먼트는 노드의 부모 id를 저장하는데, 노드의 초기 중단점은 left 필드에, 귀환 중단점은 right 필드에 저장한다.

 

다음 카테고리의 계층도를 살펴보자.

                              1 Books 12

                                   |

                         2  Programming 11

                                   |

                    -----------+-----------

                    |                              |

             3 Languages 4               5 Databases 10

                                                   |

                                     ----------+-----------

                                     |                             |

                              6 MongoDB 7                    8 dbm 9

다음 예제는 중첩셋을 사용하는 트리를 모델링한다.

db.categories.insert( { _id: "Books", parent: 0, left: 1, right: 12 } )

db.categories.insert( { _id: "Programming", parent: "Books", left: 2, right: 11 } )

db.categories.insert( { _id: "Languages", parent: "Programming", left: 3, right: 4 } )

db.categories.insert( { _id: "Databases", parent: "Programming", left: 5, right: 10 } )

db.categories.insert( { _id: "MongoDB", parent: "Databases", left: 6, right: 7 } )

db.categories.insert( { _id: "dbm", parent: "Databases", left: 8, right: 9 } )

 

​여러분은 노드의 후손들을 얻기 위해 쿼리할 수 있다.

var databaseCategory = db.categories.findOne( { _id: "Databases" } );

db.categories.find( { left: { $gt: databaseCategory.left }, right: { $lt: databaseCategory.right } } );

 

​중첩셋 패턴은 하위트리를 찾는데 빠르고 효율적인 해결책을 제공하지만 트리 구조를 변경하는데는 비효율적이다. 이처럼, 이 패턴은 변하지 않는 정적인 트리에 있어서는 최선이다.

 

 

특정 애플리케이션 문맥 모델링하기

 

원자적 연산을 위한 데이터 모델링하기

​패턴 

​MongoDB에서, 쓰기 연산, 즉 db.collection.update(), db.collection.findAndModify(), db.collection.remove() 들은 단일 도큐먼트 수준에서 원자적이다. 반드시 함께 업데이트 되어야 하는 필드들에 대해서, 같은 도큐먼트 내에 필드들을 내장하는 것은 그 필드들이 원자적으로 업데이트 되는 것을 보장한다.

 

예를 들어, 여러분이 책에 관한 정보를 유지하고 있는데, 대출 가능한 책의 수량과 현재 대출 정보가 이에 포함된다.

 

책의 대출 가능한 수량과 대출 정보는 동기화가 되어야 한다. 그렇기 때문에, 같은 도큐먼트 내에 available 필드와 checkout 필드를 내장시키는 것은 여러분이 이 둘 필드들을 원자적으로 업데이트 하는 것을 보장한다.

{

    _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",

    available: 3,

    checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]

}

 

새로운 대출 정보를 업데이트 하려면, 여러분은 db.collection.update()를 사용하여 available 필드와 checkout 필드 모두를 원자적으로 업데이트 할 수 있다.

db.books.update (

   { _id: 123456789, available: { $gt: 0 } },

   {

     $inc: { available: -1 },

     $push: { checkout: { by: "abc", date: new Date() } }

   }

)

 

이 연산은 연산의 상태에 대한 정보를 포함하는 WriteResult() 객체를 리턴한다.

 WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

nMatched 필드는 업데이트 조건에 매칭하는 도큐먼트가 1개임을 보여주고, nModified는 1개의 도큐먼트를 업데이트 했음을 보여준다.

 

키워드 검색을 지원하는 데이터 모델링하기

​키워드 검색은 텍스트 검색 혹은 전체 텍스트 검색과 같은 것이 아니고, 텍스트 처리 특징들을 제공하지 않는다. MongoDB 2.4부터는 텍스트 검색을 제공한다.

 

만약 애플리케이션이 텍스트를 담고 있는 필드의 내용에 대해 쿼리를 수행할 필요가 있다면, 그 텍스트에 정확한 매칭을 수행하거나 정규 표현식 패턴 매칭을 하기 위한 $regex를 사용할 수 있다. 하지만텍스트에 대한 많은 연산들에서, 이런 방법들은 애플리케이션의 요구사항을 만족시키지 않는다.

 

이번 패턴은 MongoDB를 사용한 키워드 검색을 지원하는 한 방법을 설명하는데, 같은 도큐먼트에 텍스트 필드로 배열로 저장된 키워드를 사용한다. 다중키 인덱스와 함께, 이 패턴은 애플리케이션의 키워드 검색 연산을 지원할 수 있다.

 

​패턴 

도큐먼트 구조에 키워드 기반 쿼리 지원을 추가하려면, 도큐먼트 안에 배열 필드를 생성하고 문자열로 된 키워드를 그 배열에 넣는다. 그런 다음에 여러분은 그 배열에 다중키 인덱스를 생성하고 배열로부터 값을 선택하는 쿼리를 생성할 수 있다.
 
예를 들어, 토픽 기반 검색을 제공하는 도서관 책 콜렉션이 있다고 하자. 각 도서에 대해, 여러분은 topics 배열을 추가하고, 주어진 도서에 필요한 만큼의 키워드를 추가할 수 있다.
 
Moby-Dick 도서에 대해, 여러분은 다음과 같은 도큐먼트를 가질 수 있다.

{ title : "Moby-Dick" ,

  author : "Herman Melville" ,

  published : 1851 ,

  ISBN : 0451526996 ,

  topics : [ "whaling" , "allegory" , "revenge" , "American" ,

    "novel" , "nautical" , "voyage" , "Cape Cod" ]

}

 

그러면, topics 배열에 다중키 인덱스를 생성한다.

 db.volumes.createIndex( { topics: 1 } )

 
다중키 인덱스는 topics 배열 안의 각 키워드에 대한 분리된 인덱스 엔트리를 생성한다. 예를 들어, 인덱스는 whaling에 대해 하나의 엔트리와 allegory에 대한 또다른 엔트리를 포함한다.
 
그런 다음, 여러분은 키워드에 기반한 쿼리를 할 수 있다. 

 db.volumes.findOne( { topics : "voyage" }, { title: 1 } )

 

매우 큰 요소를 가지는 배열은 삽입시에 매우 큰 인덱싱 비용을 초래할 것이다.

 

키워드 인덱스의 한계

​MongoDB는 특정 데이터 모델과 다중키 인덱스를 사용하여 키워드 검색을 지원한다. 하지만 이들 키워드 인덱스는 다음과 같은 관점에서 보면 전체 텍스트 검색에는 적당하지 않다.

  • Stemming. MongoDB에서의 키워드 쿼리는 루트 또는 연관 단어를 위해 키워드를 파싱할 수 없다.
  • Synonyms. 키워드 기반 검색 특징은 애플리케이션 층위에서 유의어 또는 관련 쿼리 지원을 제공해야 한다.
  • Ranking. 이 문서에서 서술된 키워드 검색은 검색 결과 비중을 기록하는 방법을 제공하지 않는다.
  • Asynchronous Indexing. MongoDB는 인덱스를 동기적으로 구축하는데, 이는 키워드를 위해 사용되는 인덱스는 항상 현재이고 실시간으로 동작한다는 것을 의미한다. 하지만, 비동기 벌크 인덱스가 몇몇 작업에서는 좀 더 효율적일 수 있다.
 

화폐 데이터 모델링하기

​개관 

​화폐 데이터를 다루는 애플리케이션은 종종 통화의 분수 단위를 파악해야 하는 경우가 있고, 계산을 할 때 정확한 단위로 십진 반올림을 해야 한다. 이진 기반 부동소수점 연산은 정확한 십진 분수를 표현할 수 없고 화폐 계산에 적당하지 않은 어림치가 생긴다. 이런 제약은 화폐 데이터를 모델링하는데 중요한 고려사항이다.

 

MongoDB에서 수치와 비수치를 사용하는 화폐 데이터를 모델링하는 몇가지 접근방법이 있다.

 

수치적 모델은 만약 여러분이 정확하게 수학적으로 올바른 매칭으로 쿼리할 필요가 있거나 서버측 계산, 즉 $inc, $mul, 그리고 통합 프레임워크 계산을 수행할 필요가 있을 때 적당하다.

 

만약 화폐 데이터에 대해 서버측 계산이 필요 없거나 서버측 어림치로 충분하다면, 비수치적 모델을 사용한 화폐 데이터 모델링이 적당할 것이다.

 

수치적 모델

​십진 BSON 타입을 사용하기 

스케일 인자(Scale Factor)를 사용하기

비수치적 모델

 

시간 데이터 모델링하기

​개관 

​MongoDB는 기본적으로 UTC 시간을 저장한다. 그리고 모든 지역 시간 표현을 이 형태로 변환한다. 변경되지 않은 지역 시간으로 운영하거나 보고해야만 하는 애플리케이션은 UTC 타임스탬프와 함께 시간대를 저장하여, 애플리케이션 로직에서 원래의 지역 시간을 계산할 수 있다.

 

예제

​MongoDB shell 에서, 여러분은 현재 날짜와 현재의 UTC 편차를 저장할 수 있다.

var now = new Date();

db.data.save( { date: now,

                offset: now.getTimezoneOffset() } );

 

​여러분은 저장된 편차를 적용하여 원래의 지역 시간을 재구성할 수 있다.

var record = db.data.findOne();

var localNow = new Date( record.date.getTime() -  ( record.offset * 60000 ) );

 

 

*** 데이터 모델 참조 ***

 

데이터베이스 참조

 

​MongoDB는 조인을 지원하지 않는다. MongoDB에서는 조인의 필요성을 제거하기 위해 몇몇 데이터는 역정규화 또는 도큐먼트 안에 관련된 데이터가 저장되어 있다. 하지만 어떤 경우엔 관련된 정보를 분리된 도큐먼트에, 보통은 다른 콜렉션 혹은 데이터베이스에 저장하는 것이 자연스러울 때가 있다.

 

MongoDB 애플리케이션은 다음 2가지 방법중의 하나를 사용한다.

  • 수동 참조(Manual Reference)는 여러분이 한 도큐먼트의 _id 필드롤 다른 도큐먼트에 참조로서 저장한다. 그러면 애플리케이션은 관련된 데이터를 리턴하기 위해 두번째 쿼리를 사용할 수 있다. 이러한 참조는 간단하고 대부분의 경우에 충분하다.
  • DBRefs는 첫번째 도큐먼트의 _id 필드, 콜렉션명, 그리고 선택적으로 데이터베이스명을 사용하여 또다른 도큐먼트로의 참조이다. 이들 이름들을 포함시킴으로써, DBRefs는 여러 콜렉션에 위치한 도큐먼트들이 단일 콜렉션에서의 도큐먼트와 좀 더 쉽게 연결되게 해준다.
 
DBRefs를 반드시 사용해야 하는 이유가 있는 것이 아니라면, 대신 수동 참조를 사용하라.

 

수동 참조

​배경 

​수동 참조 사용은 한 도큐먼트의 _id 필드를 다른 도큐먼트에 포함시키는 것이다. 그러면 애플리케이션은 두번째 쿼리를 발행하여 참조된 필드를 해결한다.

 

과정

​다음의 연산은 2개의 도큐먼트를 삽입하는데, 첫번째 도큐먼트의 _id 필드를 두번째 도큐먼트에 참조로 사용한다.

original_id = ObjectId()

 

db.places.insert({

    "_id": original_id,

    "name": "Broadway Center",

    "url": "bc.example.net"

})

 

db.people.insert({

    "name": "Erin",

    "places_id": original_id,

    "url":  "bc.example.net/Erin"

})

 

그러면 쿼리가 people 콜렉션에서 도큐먼트를 리턴하면, 필요하다면 여러분은 places 콜렉션에서 places_id 필드에 의해 참조되는 도큐먼트를 위해 두번째 쿼리를 사용할 수 있다.

 

사용

​두 도큐먼트 사이의 관계를 저장하기 위하는 거의 모든 경우에, 수동 참조를 사용하라. 참조는 생성하기 간단하고 애플리케이션은 필요할 때 참조를 해결할 수 있다.

 

수동 연결의 유일한 제약은 이들 참조가 데이터베이스명과 콜렉션명을 동반하지 않는다는 것이다. 만약 여러분이 단일 콜렉션 안에 하나 이상의 콜렉션에 있는 도큐먼트들과 연관된 도큐먼트를 가진다면, DBRefs 사용을 고려할 필요는 있다.

 

DBRefs

​배경 

​DBRefs는 특정 참조 타입 이라기 보다는 도큐먼트를 표현하기 위한 규약이다. 이들은 _id 필드의 값 뿐만 아니라 콜렉션 이름, 그리고 어떤 경우엔 데이터베이스 이름 까지도 포함한다.

 

포맷

​DBRefs는 다음 필드들을 가진다.

 

$ref

이 필드는 참조되는 도큐먼트가 상주하고 있는 콜렉션의 이름을 가진다.

$id

이 필드는 참조되는 도큐먼트 안의 _id 필드의 값을 포함한다.

$db

이 필드는 선택적인데, 참조되는 도큐먼트가 상주하고 있는 데이터베이스의 이름을 가진다. 오직 몇몇 드라이버에서만 이것을 지원한다.

 

DBRef 도큐먼트는 다음과 같다.

 { "$ref" : <value>, "$id" : <value>, "$db" : <value> }

 

creator 필드안에 DBRef를 저장한 도큐먼트는 다음과 같다.

{

  "_id" : ObjectId("5126bbf64aed4daf9e2ab771"),

  // .. application fields

  "creator" : {

                  "$ref" : "creators",

                  "$id" : ObjectId("5126bc054aed4daf9e2ab772"),

                  "$db" : "users"

               }

}

 

DBRef 안의 필드 순서는 중요하다. 여러분은 DBRef를 사용할 때 위에 나타난 순서를 지켜야만 한다.

 

DBRefs를 위한 드라이버 지원

사용

 

[출처] https://blog.naver.com/oidoman/221230255258

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
공지 오라클 기본 샘플 데이터베이스 졸리운_곰 2014.01.02 86167
공지 [SQL컨셉] 서적 "SQL컨셉"의 샘플 데이타 베이스 SAMPLE DATABASE of ORACLE 가을의 곰을... 2013.02.10 78656
공지 [G_SQL] Sample Database 가을의 곰을... 2012.05.20 95391
46 [데이터분석 & 데이터 사이언스] 수많은 데이터 사이언티스트들이 직장을 떠나는 이유는 무엇인가? file 졸리운_곰 2025.03.09 901
45 [데이터분석][파이썬][python] 한글 글꼴 사용 (matplotlib) 졸리운_곰 2024.04.18 1360
44 [데이터분석 & 데이터 사이언스] 데이터에 관한 꼭 알아야 할 오해와 진실 12가지 졸리운_곰 2024.01.17 1315
43 [데이터분석][파이썬][python] Awesome Dash Awesome file 졸리운_곰 2021.07.10 2339
42 [데이터분석][파이썬][python] ???? Introducing Dash ???? file 졸리운_곰 2021.07.10 1606
41 [dataset] (한글) 욕설 감지 데이터셋 file 졸리운_곰 2021.05.12 1559
40 [데이터분석][python] Dash를 사용하는 초보자 및 기타 모든 사용자를위한 Python의 대시 보드 file 졸리운_곰 2021.04.14 1762
39 [데이터분석][python] Dash를 사용하는 초보자 및 기타 모든 사용자를위한 Python의 대시 보드 file 졸리운_곰 2021.04.14 1603
38 [데이터분석][데이터 사이언스][python][Dash] Python, Dash 및 Plotly를 사용하여 COVID-19 사례 데이터 시각화 file 졸리운_곰 2021.03.28 1501
37 [데이터분석][머신러닝] When not to use machine learning or AI Adventures in wishful thinking, nonstationarity, and pattern-finding / 기계 학습 또는 AI를 사용하지 않아야하는 경우 희망찬 사고, 비정상 성, 패턴 찾기의 모험 file 졸리운_곰 2021.03.28 21621
36 [MSA][머신러닝] 쿠버네티스 기반의 End2End 머신러닝 플랫폼 Kubeflow #1 - 소개 file 졸리운_곰 2021.03.21 1135
35 [데이터사이언스] 데이터 과학자를위한 3 가지 훌륭한 디자인 패턴, 3 Great Design Patterns for Data Scientists file 졸리운_곰 2021.03.04 779
34 [데이터분석] 시계열 데이터에 AI를 사용하는 이유는 무엇입니까? file 졸리운_곰 2021.02.28 1191
33 [데이터분석] AI 예측 및 이상 탐지를위한 시계열 데이터 전처리 file 졸리운_곰 2021.02.28 1031
32 [데이터분석] bitcoin analysis 비트 코인 시계열 데이터에 대한 AI 이상 탐지 file 졸리운_곰 2021.02.27 1588
31 [데이터분석 & 데이터 사이언스] How To Create a Data Science Portfolio Website file 졸리운_곰 2021.02.14 1823
30 [데이터수집4] 오픈 API 데이터 수집 (소셜미디어 데이터 수집) file 졸리운_곰 2020.06.12 1951
29 [데이터수집3] 관계형 데이터베이스 데이터 수집 file 졸리운_곰 2020.06.12 1317
28 [데이터수집2] 분산시스템 로그 수집 (빅데이터 수집) file 졸리운_곰 2020.06.12 1492
27 [데이터수집1] 웹 크롤링, 웹 스크래핑 file 졸리운_곰 2020.06.12 1804
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED