MongoDB에서 데이터를 저장하는 기본 단위는 Document다. Document는 JSON과 유사한 형태의 BSON 형식으로 저장되며, 생성 시점에 어떤 형식이든 자유롭게 정의할 수 있다. 같은 Collection에 속해 있어도 각 Document는 서로 다른 필드 구조를 가질 수 있으며, 스키마가 고정되어 있지 않다.
하나의 Document는 자신의 데이터에 대해 완결성(자기완결성)을 갖는다.
모든 Document는 반드시 _id
필드를 가져야 하며, 이는 해당 Document의 Primary Key 역할을 한다. 사용자가 직접 지정할 수도 있고, 지정하지 않으면 MongoDB가 ObjectId
형태의 값을 자동으로 생성해준다.
우리가 RDBMS에서 데이터를 다룰 때는 테이블의 컬럼이 미리 정의되어 있고, 데이터는 각 Row 단위로 저장된다고 했다.
예를 들어 SELECT 쿼리를 실행하면 0 row, 1 row 등 결과가 Row 단위로 나오는데,
MongoDB에서는 이 Row에 해당하는 것이 바로 Document라고 생각하면 된다.
모든 Document는 고유값을 뜻하는 _id 필드를 반드시 가진다. _id는 직접 지정할 수도 있고, 지정하지 않으면 ObjectId 형식의 데이터가 자동 생성되어 데이터 생성(삽입) 시점에 할당된다.
ObjectId는 12bytes로 다음의 데이터의 조합이다.
직접 _id를 지정하지 않고, ObjectId를 쓴다면 다음과 같은 장점이 있다.
ObjectId.getTimestamp()
메서드를 통해서 별도의 필드 없이 생성 시점을 가져올 수 있다.JSON style의 binary 포맷이라고 생각하면 된다. 하지만 BSON이 가질 수 있는 데이터 타입은 좀 더 상세하다. 다음 링크를 참고하면 어떤 타입을 어떤 정의로 사용할 수 있는지 알 수 있다.
https://www.mongodb.com/docs/manual/reference/bson-types/
Document를 저장하기 위한 논리적인 묶음을 Collection이라고 한다. RDBMS의 Table과 유사하다고 생각하면 된다.
MongoDB는 Document Store로서 Document의 형식에 제약이 없지만, Collection 단위에서 같은 형식(key:value 에서 key 값이 같은 데이터들 )(필드 이름, 값의 데이터 타입 등)을 가지도록 제약을 걸 수 있다. 시스템의 요구사항으로 형식이 다른 데이터가 들어가면 안되는 경우에는 Schema Validation 기능을 사용
한다. (Validation 기능으로 collection 자체에다가 제약을 걸어서 그거에 맞지 않는 데이터가 들어오면 error 발생)
Schema Validation을 사용하지 않더라도, 스키마 규칙을 프로그래밍 모델로라도 가지고 사용하는 것을 추천한다. 이 경우 optional field가 많아도 상관이 없다. 다만, optional이 많으면 정적타입 언어를 쓰는 경우 null-check를 신경써야하는 불편함이 있다.
하나의 MongoDB 서버(또는 클러스터) 안에서는 여러 개의 Database를 논리적으로 분리할 수 있다.
주로 하나의 서비스나 클라이언트 사용자 단위로 나누며, 접속 권한을 제한하거나 사용자별 데이터 격리를 위해 사용된다.
예를 들어, 어떤 클라이언트는 특정 Database에만 접속하도록 하고, 그 안에 필요한 Collection들을 모아두는 방식이다.
이런 식으로 구분하면 보안 및 운영 측면에서 유리하다.
반면, 특별한 이유 없이 Database를 지나치게 나누면 오히려 번거로울 수 있다.
MongoDB에서는 Database와 Collection을 명시적으로 지정해야 하기 때문에,
코드나 커넥션 설정에서 다룰 객체가 많아지고 관리가 복잡해질 수 있다.
그래서 Database는 필요에 따라 논리적 단위로 구분하되, 너무 세분화하지 않는 것이 일반적이다.
이처럼 MongoDB의 Database는 논리적 분리와 권한 관리를 위한 단위로 사용된다는 점만 간단히 기억해두자.
MongoDB는 BSON 형식을 사용하기 때문에, 하나의 필드 안에 또 다른 BSON Object(JSON 객체)를 중첩해서 가질 수 있다. 즉, 필드 내부에 또 필드가 있는 구조를 자유롭게 설계할 수 있으며, 이와 같은 중첩 구조에 대해서도 검색이나 집계 연산을 수행할 수 있다.
이러한 유연성 덕분에 객체 지향적으로 데이터를 저장할 수 있고, 실제 코드 객체와의 매핑에도 용이하다는 장점이 있다.
반면, 중첩 필드가 깊어질수록 쿼리 성능은 점점 떨어지기 때문에 단순히 데이터 저장의 편의성만 고려하기보다는 검색 효율성까지 포함하여 Document 구조를 설계하는 것이 중요하다.
이런 유연한 스키마 구조는 관계형 데이터베이스(MySQL 등)와의 주요 차이점 중 하나다.
MySQL에서는 스키마가 엄격하게 정해져 있어 필드를 추가하거나 수정하려면 테이블 구조 자체를 변경해야 하며, 이로 인해 데이터 마이그레이션 작업이 필요해진다.
마이그레이션 과정에서는 서비스에 다운타임이 발생할 수 있고, 순차적 작업, 데이터 정합성, 오류 처리, 고객 CS 대응 등 여러 가지 운영상 복잡한 문제들이 생길 수 있다.
이러한 부담 없이 먼저 데이터를 빠르게 설계하고 저장해두고, 실제 서비스 흐름 속에서 필요한 구조로 점차 다듬어갈 수 있다는 것이 MongoDB의 큰 장점이다.
또한, 시스템이나 서비스 규모가 작고 데이터 양이 많지 않다면 중첩 필드나 비정형 구조로 인한 성능 차이는 크게 체감되지 않을 수 있다.
이런 경우에는 초기부터 성능 최적화에 지나치게 매달리기보다는, 개발 생산성을 우선해 객체지향적인 모델링을 활용하는 것이 더 유리할 수 있다.
실제로 문제가 발생했을 때 그때 성능 튜닝이나 Document 구조 리팩토링을 진행해도 늦지 않다.
참고: https://www.mongodb.com/docs/manual/reference/database-references/
MongoDB에서도 RDBMS에서 Foreign Key를 지정하는 것처럼, 다른 컬렉션(Collection)이나 데이터베이스(Database)의 특정 도큐먼트(Document)를 참조할 수 있는 기능이 있다.
이를 위해 MongoDB는 두 가지 참조 방식을 제공한다.
하지만 어떤 방식을 사용하더라도 RDBMS처럼 Cascade 동작을 지원하지 않기 때문에, 참조된 데이터의 변경이 자동으로 반영되거나, 원자적(Atomic)으로 동작하지 않는다. 따라서 완전한 원자성(Atomicity) 은 보장되지 않는다.
가장 단순한 참조 방식이다.
참조하고자 하는 Document의 _id
값을, 다른 Document의 필드에 저장하는 방식이다.
예를 들어 A 컬렉션의 문서가 B 컬렉션의 문서를 참조하려면, B 문서의 _id
값을 A 문서의 필드에 직접 저장한다.
이 경우 MongoDB는 내부적으로 join을 수행하지 않기 때문에, 참조된 데이터를 조회하려면 두 번의 쿼리를 별도로 수행해야 한다.
MongoDB가 제공하는 공식 참조 규약(convention)으로, 다른 Document를 참조하기 위해 필요한 정보를 특정한 객체 형식으로 저장하는 방식이다.
이 객체는 일반적으로 다음과 같은 필드들로 구성된다:
$ref
: 참조 대상의 컬렉션 이름$id
: 참조 대상 문서의 _id
$db
: 참조 대상이 속한 데이터베이스 이름 (선택 사항)이 DB Ref 형식은 일부 MongoDB 클라이언트 라이브러리에서 자동으로 처리되기도 하지만, 언어별로 지원 방식과 범위가 다르기 때문에 실제 사용 전에 해당 언어나 프레임워크의 문서를 확인하는 것이 필요하다.
예를 들어, Java 계열에서는 이 DB Ref 구조를 그대로 다루기엔 불편한 점이 있는데, 이를 보완하기 위해 Spring Data MongoDB 같은 라이브러리가 제공된다.
이 라이브러리는 JPA 스타일의 추상화를 통해 MongoDB 참조를 보다 편리하게 다룰 수 있게 해주며, Java 애플리케이션 개발 시 MongoDB와의 통합 작업을 보다 수월하게 만들어준다
MongoDB는 기본적으로 하나의 Document에 대한 연산에만 원자성(Atomicity) 을 보장한다.
product1
이라는 Document에 대해 한 사용자가 insert, 다른 사용자가 update, 또 다른 사용자가 read를 동시에 시도하더라도 각각의 연산은 독립적으로 처리된다.RDBMS에서는 트랜잭션이 하나의 세션 내에서만 가시성을 갖는다.
MongoDB 4.0 이상(Replica Set), 4.2 이상(Sharded Cluster)에서는 여러 Document를 하나의 트랜잭션으로 묶어 처리할 수 있는 Multi-Document Transaction 기능을 제공한다.
이를 통해 RDBMS처럼 복수 Document에 대한 일괄 처리 및 롤백이 가능하지만, 다음과 같은 제약이 존재한다:
따라서 MongoDB에서 트랜잭션을 도입하고자 한다면, 반드시 공식 문서를 통해 기능 범위와 제한 사항을 충분히 이해한 후에 적용해야 한다.
“MongoDB로 RDBMS 수준의 트랜잭션을 구현하겠다”는 접근은 일반적으로 권장되지 않는다.
MongoDB는 다음과 같은 시스템에 더 적합하다:
아키텍처 설계 시에는 MongoDB가 제공하는 특성이 내 시스템의 요구와 얼마나 부합하는지를 먼저 검토한 후 도입 여부를 결정해야 한다.
만약 회사 정책 또는 기존 시스템 구조로 인해 MongoDB를 반드시 사용해야 한다면:
기술 선택은 기능 구현보다 먼저 고려되어야 하는 전략적 결정이다. MongoDB의 장단점을 정확히 이해한 상태에서, 시스템 특성과 목표에 맞게 적절한 기술 스택을 선택하는 것이 중요하다.