소개
이 랩에서는 전자 상거래 애플리케이션을 위한 MongoDB 스키마를 설계하는 방법을 배웁니다. 목표는 관리 및 쿼리가 용이한 각 주문에 대한 단일의 포괄적인 문서를 만드는 것입니다. 기본적인 주문 구조를 생성하는 것으로 시작하여 상세한 고객 정보, 주문 항목 목록, 결제 세부 정보 및 상태 기록을 임베딩하여 점진적으로 풍부하게 만들 것입니다. 이 접근 방식은 실제 애플리케이션에서 MongoDB 의 문서 모델이 가진 강력함을 보여줍니다.
기본 주문 문서 생성
첫 번째 단계에서는 MongoDB 에 연결하고 새 데이터베이스를 생성합니다. 그런 다음, 다음 단계에서 구축할 스키마의 기반이 될 첫 번째 주문 문서를 삽입합니다.
먼저 MongoDB Shell 을 엽니다. 이 대화형 명령줄 인터페이스를 통해 MongoDB 데이터베이스와 통신할 수 있습니다.
mongosh
쉘에 들어가면 > 프롬프트가 표시됩니다. 이제 ecommerce라는 새 데이터베이스로 전환합니다. 데이터베이스가 존재하지 않으면 MongoDB 는 처음 데이터를 저장할 때 자동으로 생성합니다.
use ecommerce
다음으로, 문서를 삽입하여 orders라는 컬렉션을 생성합니다. 이 문서는 단일 주문을 나타내며 주문 ID, 고객 세부 정보, 주문 날짜 및 현재 상태와 같은 필수 정보를 포함합니다.
문서를 삽입하려면 다음 명령을 실행합니다.
db.orders.insertOne({
order_id: "ORD001",
order_date: new Date("2023-10-26T10:00:00Z"),
customer_id: "CUST123",
status: "pending",
total: 150.0
});
이 명령은 다음 작업을 수행합니다.
db.orders: 현재 데이터베이스 내의orders컬렉션을 지정합니다.insertOne(): 단일 문서를 삽입하는 MongoDB 메서드입니다.- 문서 자체는
order_id,order_date,customer_id,status,total에 대한 키 - 값 쌍을 가진 JSON 과 유사한 객체입니다.
성공적으로 삽입되면 MongoDB 는 새롭게 생성된 문서의 고유한 _id와 함께 확인 응답을 반환합니다.
{
"acknowledged": true,
"insertedId": ObjectId("...")
}
이제 주문에 대한 기본 구조를 생성했습니다. 다음 단계에서는 이 문서에 더 자세한 정보를 추가할 것입니다.
임베디드 고객 세부 정보로 강화
단순한 customer_id만으로는 종종 충분하지 않습니다. 실제 애플리케이션에서는 주문을 검색할 때 고객의 이름과 주소가 자주 필요합니다. customers 컬렉션에 대한 별도의 쿼리를 수행하는 대신, 이 정보를 주문 문서 내에 직접 임베딩할 수 있습니다. 이는 MongoDB 에서 읽기 성능을 향상시키는 일반적이고 강력한 패턴입니다.
이 단계에서는 상세하고 중첩된 고객 정보를 포함하도록 주문 문서를 업데이트합니다. 이전 단계에서 mongosh 쉘을 종료했다면 다시 시작하고 use ecommerce를 실행하십시오.
updateOne() 메서드를 사용하여 order_id: "ORD001"인 문서를 찾고 수정합니다. $set 연산자는 필드의 값을 지정된 값으로 바꾸고, $unset은 필드를 완전히 제거합니다.
db.orders.updateOne(
{ order_id: "ORD001" },
{
$set: {
customer: {
customer_id: "CUST123",
first_name: "John",
last_name: "Doe",
email: "john.doe@example.com",
shipping_address: {
street: "123 Main St",
city: "Anytown",
state: "CA",
zip_code: "12345"
}
}
},
$unset: {
customer_id: ""
}
}
);
이 명령에서:
- 첫 번째 인수
{ order_id: "ORD001" }는 업데이트할 문서를 선택하는 필터입니다. - 두 번째 인수에는 업데이트 연산자가 포함됩니다.
$set: 상세 정보를 포함하는 임베디드 문서인 새 필드customer를 설정하고 있습니다.$unset: 데이터 중복을 피하기 위해 기존 최상위customer_id필드를 제거하고 있습니다.
변경 사항을 확인하려면 findOne()을 사용하여 업데이트된 문서를 검색할 수 있습니다.
db.orders.findOne({ order_id: "ORD001" });
출력에는 이제 중첩된 customer 문서가 표시되며, 최상위 customer_id 필드는 사라집니다. 이 임베디드 구조는 관련 데이터를 단일 문서에 함께 유지합니다.
주문 항목 배열 추가
주문은 일반적으로 하나 이상의 제품으로 구성됩니다. 단일 주문 문서 내에서 이러한 일대다 (one-to-many) 관계를 모델링하는 가장 좋은 방법은 임베디드 문서의 배열을 사용하는 것입니다. 배열의 각 요소는 주문의 항목을 나타냅니다.
주문 문서에 항목 목록을 포함하도록 업데이트해 보겠습니다. items 필드를 추가할 것이며, 이는 배열이 됩니다. 배열의 각 객체는 제품 ID, 이름, 가격 및 수량과 같은 제품에 대한 세부 정보를 포함합니다.
다음 updateOne 명령을 실행합니다.
db.orders.updateOne(
{ order_id: "ORD001" },
{
$set: {
items: [
{
product_id: "PROD01",
name: "Laptop",
price: 1200.0,
quantity: 1
},
{
product_id: "PROD02",
name: "Mouse",
price: 25.0,
quantity: 1
}
],
total: 1225.0
}
}
);
여기서 $set을 다시 사용하여 items 배열을 추가합니다. 또한 항목 가격의 합계와 일치하도록 total 필드를 업데이트합니다. 계산된 총액을 문서에 직접 저장하는 것은 모든 읽기 작업 시 집계 (aggregation) 할 필요가 없으므로 또 다른 성능 최적화입니다.
새로운 items 배열을 보기 위해 문서를 다시 확인해 보겠습니다.
db.orders.findOne({ order_id: "ORD001" });
주문 문서 내에 임베디드된 items 배열이 표시됩니다. 이 설계는 단일 데이터베이스 쿼리로 모든 항목을 포함한 완전한 주문을 검색할 수 있도록 합니다.
결제 정보 임베딩
결제 세부 정보는 주문의 또 다른 중요한 부분입니다. 고객 정보 및 항목과 유사하게 결제 데이터도 주문 문서에 직접 임베딩할 수 있습니다. 여기에는 결제 방법, 거래 ID 및 상태가 포함됩니다.
이 단계에서는 주문에 payment 하위 문서를 추가합니다.
db.orders.updateOne(
{ order_id: "ORD001" },
{
$set: {
payment: {
method: "credit_card",
transaction_id: "TXN54321",
status: "completed"
}
}
}
);
이 명령은 method, transaction_id, status의 세 필드를 가진 payment 객체를 추가합니다. 이 정보를 임베딩하면 단일 거래와 관련된 모든 데이터가 한 곳에 위치하게 됩니다.
이제 주문 문서의 구조를 살펴보겠습니다.
db.orders.findOne({ order_id: "ORD001" });
문서에는 이제 주문, 고객, 항목 및 결제에 대한 포괄적인 정보가 포함되어 있으며, 모두 단일 읽기 작업을 통해 액세스할 수 있습니다.
주문 상태 기록 추적
주문은 "대기 중 (pending)", "처리 중 (processing)", "배송 중 (shipped)", "배송 완료 (delivered)" 등 다양한 단계를 거칩니다. 최상위 status 필드는 현재 상태를 보여주지만, 모든 상태 변경 기록을 유지하는 것이 유용한 경우가 많습니다. 이를 위해 status_history 배열을 추가할 수 있습니다.
마지막 단계에서는 주문 상태를 "처리 중 (processing)"으로 업데이트하고 status_history 배열을 구축하기 시작합니다. $push 연산자는 배열에 값을 추가하는 데 사용됩니다.
먼저 초기 "대기 중 (pending)" 상태를 기록에 추가하고 현재 상태를 "처리 중 (processing)"으로 업데이트합니다.
db.orders.updateOne(
{ order_id: "ORD001" },
{
$set: { status: "processing" },
$push: {
status_history: {
status: "pending",
timestamp: new Date("2023-10-26T10:00:00Z")
}
}
}
);
이제 기록을 완전하게 유지하기 위해 새로운 "처리 중 (processing)" 상태를 기록에 추가합니다.
db.orders.updateOne(
{ order_id: "ORD001" },
{
$push: {
status_history: {
status: "processing",
timestamp: new Date("2023-10-26T11:30:00Z")
}
}
}
);
이 접근 방식은 주문의 전체 수명 주기에 대한 완전한 감사 추적 (audit trail) 을 제공합니다. 언제든지 문서를 쿼리하여 전체 기록을 볼 수 있습니다.
db.orders.findOne({ order_id: "ORD001" });
문서에는 이제 status_history 배열이 포함되어 주문의 여정에 대한 완전한 보기를 제공합니다. MongoDB 셸을 종료하려면 exit를 입력하고 Enter 키를 누릅니다.
요약
이 실습에서는 전자상거래 주문을 위한 실용적이고 효율적인 MongoDB 스키마를 설계하는 방법을 배웠습니다. 기본 문서에서 시작하여 관련 데이터를 임베딩하여 점진적으로 풍부하게 만들었습니다. 고객 세부 정보, 주문 항목 배열, 결제 정보 및 완전한 상태 기록을 포함하는 단일 문서를 성공적으로 생성했습니다. 이 임베딩된 문서 패턴은 복잡한 조인 및 여러 쿼리의 필요성을 줄여 성능이 뛰어나고 확장 가능한 애플리케이션을 만드는 데 도움이 되는 MongoDB 스키마 설계의 핵심 개념입니다.

