소개
이 랩에서는 MongoDB 에서 일반적인 오류를 처리하는 필수 기술을 배우게 됩니다. MongoDB Shell (mongosh) 을 사용하여 연결 실패, 중복 키 오류, 데이터 유효성 검사 오류를 포함한 다양한 문제를 식별하고 해결하는 연습을 하게 됩니다. 이 랩이 끝나면 데이터베이스 작업을 더 안정적이고 견고하게 만드는 방법에 대한 실질적인 이해를 갖게 될 것입니다.
이 랩에서는 MongoDB 에서 일반적인 오류를 처리하는 필수 기술을 배우게 됩니다. MongoDB Shell (mongosh) 을 사용하여 연결 실패, 중복 키 오류, 데이터 유효성 검사 오류를 포함한 다양한 문제를 식별하고 해결하는 연습을 하게 됩니다. 이 랩이 끝나면 데이터베이스 작업을 더 안정적이고 견고하게 만드는 방법에 대한 실질적인 이해를 갖게 될 것입니다.
모든 데이터베이스 작업 시 연결 오류는 흔히 발생하는 문제입니다. 잘못된 서버 주소, 네트워크 문제 또는 데이터베이스 서버 미실행 등 여러 가지 이유로 발생할 수 있습니다. 이 단계에서는 연결 오류를 식별한 다음 성공적으로 연결하는 방법을 배우게 됩니다.
먼저, MongoDB 인스턴스가 실행되고 있지 않은 포트에 연결을 시도합니다. MongoDB 의 기본 포트는 27017입니다. 포트 27018에 연결을 시도해 보겠습니다.
터미널에서 다음 명령을 실행합니다.
mongosh "mongodb://localhost:27018"
이 명령은 쉘이 지정된 주소에서 MongoDB 서버를 찾을 수 없기 때문에 실패하고 오류를 반환합니다. 출력은 다음과 유사하게 표시됩니다.
MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27018
MongoNetworkError는 연결 실패를 명확하게 나타냅니다. ECONNREFUSED 부분은 대상 시스템이 연결을 적극적으로 거부했음을 알려주며, 이는 일반적으로 해당 포트에서 수신 대기하는 서비스가 없음을 의미합니다.
이제 올바른 포트에 연결해 보겠습니다. MongoDB 서비스는 설정 단계에서 이미 시작되었습니다. 연결하려면 인수가 없는 mongosh 명령을 실행합니다. 이렇게 하면 기본 연결 문자열 mongodb://127.0.0.1:27017이 사용됩니다.
mongosh
성공적으로 연결되면 환영 메시지와 함께 test> 프롬프트가 표시되며, 이는 기본 test 데이터베이스에 연결되었음을 나타냅니다.
Current Mongosh Log ID: ...
Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.2.6
Using MongoDB: 8.0.0
Using Mongosh: 2.2.6
...
test>
이제 MongoDB 서버에 연결되었습니다. 다음 단계를 위해 이 터미널을 열어두고 mongosh 쉘에 머물러 주십시오.
데이터 무결성을 유지하는 것은 모든 애플리케이션에 매우 중요합니다. 가장 흔한 데이터 무결성 문제 중 하나는 중복 레코드입니다. MongoDB 는 고유 인덱스 (unique index) 를 통해 이를 방지하며, 이는 인덱싱된 필드가 중복 값을 저장하지 않도록 보장합니다.
이전 단계에서 이미 mongosh 쉘에 접속해 있어야 합니다. 먼저 errorlab이라는 새 데이터베이스로 전환합니다. 데이터베이스는 처음 데이터를 저장할 때 자동으로 생성됩니다.
use errorlab
다음으로, 새 users 컬렉션의 email 필드에 고유 인덱스를 생성합니다. 이 명령은 users 컬렉션의 모든 문서가 email 필드에 대해 고유한 값을 가져야 함을 MongoDB 에 알립니다.
db.users.createIndex({ email: 1 }, { unique: true });
출력은 인덱스가 성공적으로 생성되었음을 확인합니다.
{
"numIndexesBefore": 1,
"numIndexesAfter": 2,
"createdCollectionAutomatically": true,
"ok": 1
}
이제 users 컬렉션에 문서를 삽입합니다. 컬렉션이 비어 있고 이메일이 고유하므로 이 작업은 성공합니다.
db.users.insertOne({ name: "John Doe", email: "john@example.com" });
삽입된 문서의 ID 와 함께 확인 메시지가 표시됩니다.
{
"acknowledged": true,
"insertedId": ObjectId("...")
}
다음으로, 정확히 동일한 이메일 주소를 가진 다른 문서를 삽입하려고 시도합니다.
db.users.insertOne({ name: "Jane Doe", email: "john@example.com" });
이번에는 작업이 실패합니다. MongoDB 는 특정 오류 코드인 E11000과 함께 MongoBulkWriteError를 반환하며, 이는 중복 키 오류를 나타냅니다. 이는 데이터 무결성을 보호하기 위한 예상된 동작입니다.
MongoServerError: E11000 duplicate key error collection: errorlab.users index: email_1 dup key: { email: "john@example.com" }
중복을 방지하는 것은 좋지만, 때로는 레코드가 존재하면 업데이트하고 존재하지 않으면 생성하고 싶을 때가 있습니다. 이러한 "업데이트 또는 삽입" 로직은 일반적인 요구 사항입니다. MongoDB 는 upsert 옵션을 사용하여 이를 처리하는 깔끔한 방법을 제공합니다.
john@example.com 이메일을 가진 사용자를 업데이트해 보겠습니다. upsert 옵션을 true로 설정한 updateOne 메서드를 사용합니다.
db.users.updateOne(
{ email: "john@example.com" },
{ $set: { name: "John Doe Updated", lastUpdated: new Date() } },
{ upsert: true }
);
출력은 하나의 문서가 일치하고 수정되었음을 보여줍니다. 기존 문서가 업데이트되었고 새 문서가 삽입되지 않았기 때문에 upsertedId는 null입니다.
{
"acknowledged": true,
"matchedCount": 1,
"modifiedCount": 1,
"upsertedId": null
}
이제 아직 존재하지 않는 사용자 jane@example.com에 대해 유사한 명령을 실행해 보겠습니다.
db.users.updateOne(
{ email: "jane@example.com" },
{ $set: { name: "Jane Doe", lastUpdated: new Date() } },
{ upsert: true }
);
이번에는 출력에서 matchedCount가 0 이지만 upsertedId가 나타내는 것처럼 새 문서가 생성되었음을 보여줍니다.
{
"acknowledged": true,
"matchedCount": 0,
"modifiedCount": 0,
"upsertedId": ObjectId("...")
}
결과를 확인하려면 컬렉션을 쿼리하여 모든 문서를 볼 수 있습니다. pretty() 메서드는 출력을 읽기 쉽게 포맷합니다.
db.users.find().pretty();
출력에는 두 문서가 표시됩니다. 업데이트된 이름을 가진 John 의 문서와 새로 생성된 Jane 의 문서입니다. upsert 옵션은 "생성 또는 업데이트" 시나리오를 처리하는 강력하고 원자적인 방법을 제공합니다.
데이터를 쿼리하거나 삽입된 데이터가 미리 정의된 규칙을 따르지 않을 때도 오류가 발생할 수 있습니다. 이 단계에서는 쿼리 구문 오류와 데이터 유효성 검사 오류를 살펴보겠습니다.
먼저 존재하지 않는 쿼리 연산자를 사용할 때 어떤 일이 발생하는지 살펴보겠습니다. 이는 흔한 오타입니다.
db.users.find({ name: { $invalidOperator: "John" } });
MongoDB 는 $invalidOperator를 인식하지 못하기 때문에 즉시 오류를 반환합니다.
MongoServerError[BadValue]: unknown operator: $invalidOperator
다음으로 더 강력한 기능인 스키마 유효성 검사 (schema validation) 를 살펴보겠습니다. 컬렉션에 문서를 삽입하거나 업데이트하려면 문서가 따라야 하는 규칙을 정의할 수 있습니다. name(문자열) 과 price(숫자) 를 요구하는 유효성 검사기를 사용하여 새 products 컬렉션을 생성해 보겠습니다.
db.createCollection("products", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "price"],
properties: {
name: {
bsonType: "string",
description: "must be a string and is required"
},
price: {
bsonType: "number",
description: "must be a number and is required"
}
}
}
}
});
이제 price를 숫자가 아닌 문자열로 제공하여 이 스키마를 위반하는 문서를 삽입해 보겠습니다.
db.products.insertOne({ name: "Laptop", price: "1200" });
작업은 MongoBulkWriteError로 실패합니다. Document failed validation 메시지는 이유를 명확하게 설명하여 잘못된 데이터가 데이터베이스에 들어가는 것을 방지합니다.
MongoServerError: Document failed validation
...
마지막으로 스키마를 준수하는 유효한 문서를 삽입합니다.
db.products.insertOne({ name: "Laptop", price: 1200 });
문서가 유효하므로 이 작업은 성공합니다.
{
"acknowledged": true,
"insertedId": ObjectId("...")
}
스키마 유효성 검사는 데이터베이스 내에서 직접 데이터 일관성을 강제하는 강력한 도구입니다.
이 실습에서는 mongosh 셸을 사용하여 여러 일반적인 유형의 MongoDB 오류를 처리하는 방법을 배웠습니다. 연결 오류를 식별하고 해결하는 것부터 시작했습니다. 그런 다음 고유 인덱스 (unique index) 를 생성하여 중복 키 오류를 방지함으로써 데이터 무결성을 강화했습니다. 또한 "업데이트 또는 삽입" 로직을 우아하게 처리하기 위해 upsert 옵션을 사용하는 방법을 배웠습니다. 마지막으로 쿼리 구문 오류를 탐색하고 스키마 유효성 검사 (schema validation) 를 사용하여 잘못된 데이터가 데이터베이스에 저장되는 것을 방지했습니다. 이러한 기본적인 오류 처리 기술은 MongoDB 를 사용하여 안정적이고 강력한 애플리케이션을 구축하는 데 필수적입니다.