소개
이 랩에서는 MongoDB 에서 임베디드 문서를 효과적으로 관리하는 방법을 배우게 됩니다. 임베디드 문서 또는 중첩 문서는 MongoDB 의 데이터 모델 핵심 기능으로, 단일 문서 내에 복잡하고 계층적인 데이터를 저장할 수 있게 해줍니다. 중첩된 데이터를 가진 문서 생성, 내부 특정 필드 업데이트, 요소 제거, 이러한 복잡한 구조 쿼리 등 다양한 기법을 배우게 됩니다. 또한 스키마 유효성 검사 (schema validation) 를 사용하여 일관된 데이터 구조를 강제하는 방법도 배우게 됩니다. 이러한 기술은 MongoDB 를 사용하여 견고하고 효율적인 애플리케이션을 구축하는 데 필수적입니다.
중첩 데이터로 문서 생성하기
이 단계에서는 MongoDB 에서 중첩된 구조를 가진 문서를 생성하는 방법을 배우게 됩니다. 이는 단일 문서 내에서 관련된 데이터를 모델링하는 기본적인 기술입니다.
먼저 MongoDB Shell (mongosh) 을 열어 데이터베이스와 상호 작용을 시작합니다. 별도로 명시되지 않는 한, 이 랩의 모든 후속 명령은 이 쉘 내에서 실행됩니다.
mongosh
다음으로 bookstore라는 새 데이터베이스로 전환합니다. 이 데이터베이스가 존재하지 않으면 MongoDB 는 처음 데이터를 저장할 때 자동으로 생성합니다.
use bookstore
이제 books라는 컬렉션을 생성하고 단일 문서를 삽입합니다. 이 문서는 책의 세부 정보를 나타내는 중첩된 객체와 중첩된 객체의 배열을 포함합니다.
db.books.insertOne({
title: "Advanced MongoDB",
author: {
name: "Jane Smith",
contact: {
email: "jane.smith@example.com",
phone: "+1-555-123-4567"
}
},
published: {
year: 2023,
publisher: "Tech Publications"
},
chapters: [
{ number: 1, title: "Introduction to Nested Documents" },
{ number: 2, title: "Advanced Document Structures" }
]
})
방금 생성한 문서에서:
author와published는 중첩된 문서 (객체) 입니다.author문서에는contact라는 또 다른 중첩된 문서가 포함되어 있습니다.chapters는 여러 중첩된 문서를 포함하는 배열이며, 각 문서는 챕터를 나타냅니다.
문서를 보고 구조를 확인하려면 find() 메서드를 사용합니다.
db.books.find()
다음과 같은 출력이 표시되어 문서가 올바르게 삽입되었음을 확인할 수 있습니다. _id는 MongoDB 에서 자동으로 생성되는 고유 식별자입니다.
[
{
_id: ObjectId("..."),
title: 'Advanced MongoDB',
author: {
name: 'Jane Smith',
contact: {
email: 'jane.smith@example.com',
phone: '+1-555-123-4567'
}
},
published: {
year: 2023,
publisher: 'Tech Publications'
},
chapters: [
{ number: 1, title: 'Introduction to Nested Documents' },
{ number: 2, title: 'Advanced Document Structures' }
]
}
]
중첩 필드 및 배열 요소 업데이트
문서를 생성한 후에는 종종 해당 문서의 일부를 수정해야 합니다. 이 단계에서는 중첩된 문서 및 배열 내의 특정 필드를 업데이트하는 방법을 배우게 됩니다. 이전 단계에서와 마찬가지로 mongosh 쉘에 있어야 합니다.
먼저, 저자의 연락처 정보를 업데이트해 보겠습니다. 이를 위해 $set 연산자와 점 표기법 (dot notation) 을 사용하여 변경하려는 필드의 정확한 경로를 지정합니다. 이 명령은 전화번호를 변경하고 새로운 website 필드를 추가합니다.
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $set: {
"author.contact.phone": "+1-888-999-0000",
"author.contact.website": "www.janesmith.com"
} }
)
점 표기법 "author.contact.phone"은 MongoDB 에 author 객체로 이동한 다음 contact 객체로 이동하여 phone 필드를 업데이트하도록 지시합니다.
다음으로, $push 연산자를 사용하여 chapters 배열에 새 챕터를 추가합니다.
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $push: {
chapters: {
number: 3,
title: "MongoDB Advanced Techniques"
}
} }
)
배열 내의 특정 요소도 업데이트할 수 있습니다. 첫 번째 챕터의 제목을 수정해 보겠습니다. 여기서는 위치 지정자 $ 연산자를 사용합니다. 이 연산자는 쿼리 조건 ("chapters.number": 1) 과 일치하는 첫 번째 배열 요소를 위한 자리 표시자 역할을 합니다.
db.books.updateOne(
{ title: "Advanced MongoDB", "chapters.number": 1 },
{ $set: {
"chapters.$.title": "Introduction to Nested Documents (Revised)"
} }
)
모든 변경 사항을 확인하려면 문서를 다시 검색합니다. .pretty() 메서드는 출력을 더 읽기 쉽게 형식화합니다.
db.books.find({ title: "Advanced MongoDB" }).pretty()
출력에는 업데이트된 전화번호, 새로운 웹사이트, 추가된 세 번째 챕터, 그리고 첫 번째 챕터의 수정된 제목이 표시됩니다.
중첩 필드 및 배열 요소 제거
이 단계에서는 문서의 일부를 제거하는 방법을 배우게 됩니다. 여기에는 특정 필드, 전체 중첩된 문서 및 배열의 요소를 제거하는 것이 포함됩니다.
먼저 $unset 연산자를 사용하여 저자의 연락처 정보에서 website 필드를 제거해 보겠습니다. $unset에 제공된 값 (이 경우 빈 문자열 "") 은 중요하지 않습니다. 이 연산자는 단순히 지정된 필드를 제거합니다.
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $unset: { "author.contact.website": "" } }
)
다음으로 배열에서 요소를 제거합니다. $pull 연산자를 사용하여 chapters 배열에서 세 번째 챕터 ( number: 3을 가진 챕터) 를 제거해 보겠습니다. $pull 연산자는 지정된 조건과 일치하는 모든 배열 요소를 제거합니다.
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $pull: {
chapters: { number: 3 }
} }
)
마지막으로 전체 중첩 객체를 제거할 수 있습니다. 다시 $unset 연산자를 사용하여 author 문서에서 contact 객체를 제거해 보겠습니다.
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $unset: { "author.contact": "" } }
)
이러한 제거 작업의 결과를 보려면 문서를 다시 쿼리합니다.
db.books.find({ title: "Advanced MongoDB" }).pretty()
출력에는 website 필드와 전체 contact 객체가 사라지고 chapters 배열에는 이제 두 개의 요소만 포함된 것을 볼 수 있습니다.
중첩 데이터로 문서 쿼리하기
쿼리는 기본적인 데이터베이스 작업입니다. 이 단계에서는 중첩된 객체 및 배열 내의 값을 기반으로 문서를 쿼리하는 방법을 배우게 됩니다. 이러한 예제를 위해 깨끗한 데이터 세트를 확보하기 위해 먼저 기존 books 컬렉션을 삭제합니다.
db.books.drop()
이제 쿼리 연습을 위해 서로 다른 중첩 구조를 가진 몇 개의 새 문서를 삽입합니다.
db.books.insertMany([
{
title: "MongoDB Essentials",
author: {
name: "John Doe",
experience: { years: 5, specialization: "Database Design" }
},
tags: ["beginner", "database", "nosql"],
chapters: [
{ number: 1, title: "Introduction", pages: 25 },
{ number: 2, title: "Advanced Concepts", pages: 45 }
]
},
{
title: "Advanced Database Techniques",
author: {
name: "Jane Smith",
experience: { years: 8, specialization: "Distributed Systems" }
},
tags: ["advanced", "distributed", "nosql"],
chapters: [
{ number: 1, title: "System Design", pages: 35 },
{ number: 2, title: "Performance Optimization", pages: 55 }
]
}
])
중첩된 문서의 필드로 책을 찾으려면 점 표기법 (dot notation) 을 사용합니다. 이 쿼리는 "John Doe"가 작성한 책을 찾습니다.
db.books.find({ "author.name": "John Doe" })
중첩된 구조로 더 깊이 들어갈 수 있습니다. 이 쿼리는 저자의 전문 분야가 "Database Design"인 책을 찾습니다.
db.books.find({ "author.experience.specialization": "Database Design" })
배열에 특정 값이 포함된 문서를 찾으려면 배열 필드를 직접 쿼리할 수 있습니다. 이 쿼리는 "nosql" 태그가 지정된 모든 책을 찾습니다.
db.books.find({ tags: "nosql" })
또한 배열 요소가 특정 조건을 충족하는 문서를 쿼리할 수도 있습니다. 이 쿼리는 $gt (greater than) 연산자를 사용하여 40 페이지보다 긴 챕터가 하나 이상 있는 책을 찾습니다.
db.books.find({ "chapters.pages": { $gt: 40 } })
마지막으로 여러 조건을 결합할 수 있습니다. 이 쿼리는 "advanced" 태그가 지정되었고 5 년 이상의 경력 ($gte는 greater than or equal to 를 의미) 을 가진 저자가 작성한 책을 찾습니다.
db.books.find({
"author.experience.years": { $gte: 5 },
tags: "advanced"
})
스키마 유효성 검사로 문서 구조 강제 적용
데이터 일관성을 유지하기 위해 MongoDB 는 JSON 스키마 유효성 검사 (JSON Schema validation) 를 사용하여 컬렉션의 문서에 특정 구조를 강제할 수 있습니다. 이 단계에서는 미리 정의된 구조를 모든 문서가 준수하도록 하기 위해 유효성 검사기 (validator) 를 사용하여 새 컬렉션을 생성합니다.
먼저 courses라는 새 컬렉션을 생성합니다. 생성 시 스키마 규칙을 포함하는 validator 옵션을 전달합니다.
db.createCollection("courses", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["title", "instructor", "duration", "topics"],
properties: {
title: {
bsonType: "string",
description: "must be a string and is required"
},
instructor: {
bsonType: "object",
required: ["name", "email"],
properties: {
name: { bsonType: "string" },
email: {
bsonType: "string",
pattern: "^.+@.+$"
}
}
},
duration: {
bsonType: "int",
minimum: 1,
maximum: 100
},
topics: {
bsonType: "array",
minItems: 1,
items: { bsonType: "string" }
}
}
}
}
})
이 스키마는 모든 문서에 title, instructor, duration, topics 필드가 있어야 함을 요구합니다. 또한 각 필드의 데이터 유형을 정의하며, instructor 객체와 topics 배열에 대한 중첩 규칙도 포함합니다.
이제 이 규칙을 준수하는 문서를 삽입해 보겠습니다. 이 작업은 성공해야 합니다.
db.courses.insertOne({
title: "MongoDB Advanced Techniques",
instructor: {
name: "Jane Smith",
email: "jane.smith@example.com"
},
duration: 40,
topics: ["Nested Documents", "Schema Validation"]
})
다음으로 스키마 규칙을 위반하는 문서를 삽입해 보겠습니다. 이 문서는 instructor.name에 잘못된 데이터 유형, 잘못된 이메일 형식, 허용 범위를 벗어난 duration, 그리고 비어 있는 topics 배열을 가지고 있습니다.
db.courses.insertOne({
title: "Invalid Course",
instructor: {
name: 123,
email: "invalid-email"
},
duration: 200,
topics: []
})
이 삽입은 실패하며 MongoDB 는 Document failed validation 오류를 반환합니다. 이는 일관성 없는 데이터가 저장되는 것을 방지하고 데이터베이스 무결성을 유지하는 데 도움이 됩니다.
요약
이 실습에서는 MongoDB 에서 중첩된 문서를 관리하는 기본적인 기술을 배웠습니다. 객체와 배열을 포함한 복잡한 중첩 구조로 문서를 생성하는 것부터 시작했습니다. 그런 다음 점 표기법 (dot notation) 과 $set, $push와 같은 연산자를 사용하여 특정 필드를 업데이트하는 연습을 했습니다. 또한 $unset 및 $pull을 사용하여 데이터를 제거하는 방법도 배웠습니다. 더 나아가 중첩된 데이터에 대한 대상 쿼리를 수행하는 방법을 탐색했으며, 마지막으로 컬렉션에 JSON 스키마 유효성 검사기 (JSON Schema validator) 를 정의하고 적용하여 데이터 무결성을 강제하는 방법을 배웠습니다. 이러한 기술은 MongoDB 의 유연한 문서 모델을 효과적으로 활용하는 애플리케이션을 구축하는 데 매우 중요합니다.

