MongoDB Academy · บทเรียน

การพัฒนาสคีมาโดยไม่หยุดให้บริการ

ผู้เรียนจะอัปเดตตัวตรวจสอบที่มีอยู่ในคอลเลกชันที่กำลังใช้งานจริง และเขียนสคริปต์ย้ายข้อมูลเพื่อเติมเอกสารให้เป็นรูปแบบใหม่

บทเรียน 4 จาก 413 ขั้นตอน

การพัฒนาสคีมาโดยไม่หยุดให้บริการ เป็นบทเรียน MongoDB Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน MongoDB Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน

บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ

The Challenge of Schema Evolution

As your application grows, requirements change and your MongoDB schema must evolve. Unlike relational databases, you cannot run a blocking ALTER TABLE that locks the entire table during migration. MongoDB's flexibility means old and new document shapes can coexist in the same collection, which requires a deliberate migration strategy to keep the application working while the schema transitions.

Step 1: Update the Validator in Warn Mode

Begin every schema migration by updating the collection's validator to reflect the new schema, but with validationAction: 'warn'. This allows existing non-conforming documents to remain and be updated without errors while you measure how many documents need to be backfilled. New writes from updated application code will conform to the new schema.

// Add a new required field 'phoneNumber' to the validator
db.runCommand({
  collMod: 'users',
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['name', 'email', 'phoneNumber'],
      properties: {
        name:        { bsonType: 'string' },
        email:       { bsonType: 'string' },
        phoneNumber: { bsonType: 'string' }
      }
    }
  },
  validationLevel: 'moderate',
  validationAction: 'warn'
});

Step 2: Update the Application Code

Deploy the updated application code that writes documents conforming to the new schema. New documents will now include the new fields. Old documents written before the schema change remain in the collection in their original shape. During this phase, your application code must handle both document shapes—for example, by providing a default value when the new field is absent.

// Application code that handles both old and new document shapes
async function getUserPhone(userId) {
  const user = await db.collection('users').findOne({ _id: userId });
  // Provide a fallback for documents written before the migration
  return user.phoneNumber || 'Not provided';
}

Step 3: Write a Backfill Migration Script

A backfill script iterates over all documents missing the new field and sets a default value. Run it in small batches to avoid locking resources or spiking server load. Use bulkWrite with ordered: false for efficiency, and track progress with logging so you can resume if interrupted.

// Backfill: set phoneNumber to '' for documents that lack it
const collection = db.collection('users');
const cursor = collection.find({ phoneNumber: { $exists: false } });

const batchSize = 500;
let batch = [];

for await (const doc of cursor) {
  batch.push({
    updateOne: {
      filter: { _id: doc._id },
      update: { $set: { phoneNumber: '' } }
    }
  });
  if (batch.length === batchSize) {
    await collection.bulkWrite(batch, { ordered: false });
    console.log('Processed', batchSize, 'docs');
    batch = [];
  }
}
if (batch.length) await collection.bulkWrite(batch, { ordered: false });
console.log('Backfill complete');

Step 4: Switch to Strict Error Mode

After the backfill is complete and you have verified that all documents conform to the new schema, switch validationLevel to strict and validationAction to error. From this point on, any write that violates the schema is rejected. Monitor the application for unexpected errors in the first hours after switching to catch any edge case that the backfill missed.

// Enable full enforcement after backfill is verified
db.runCommand({
  collMod: 'users',
  validationLevel: 'strict',
  validationAction: 'error'
});
console.log('Full schema enforcement enabled');

Renaming a Field Safely

To rename a field (e.g., fullName → name), first add name to new documents while the application still reads fullName as a fallback. Then backfill by copying fullName to name using $rename or $set. Finally, update the application to write and read only name, and remove fullName from old documents.

// Backfill: rename fullName to name for all existing documents
db.users.updateMany(
  { fullName: { $exists: true }, name: { $exists: false } },
  [{ $set: { name: '$fullName' } }, { $unset: 'fullName' }]
);

The Schema Versioning Pattern

For complex long-running migrations, add a schemaVersion field to every document. Application code checks this field and applies a transformation function for each older version before processing the document. New writes always include the latest schemaVersion. This gives you a controlled, auditable upgrade path and allows multiple schema generations to coexist indefinitely.

// Insert new document with schema version
db.products.insertOne({
  schemaVersion: 2,
  name: 'Widget Pro',
  priceUSD: 49.99,
  categories: ['electronics']
});

// Application transformer
function normalise(doc) {
  if (doc.schemaVersion === 1) {
    // v1 used 'price' instead of 'priceUSD'
    doc.priceUSD = doc.price;
    delete doc.price;
    doc.schemaVersion = 2;
  }
  return doc;
}

Adding a New Optional Field Safely

Adding a new optional field is the simplest schema evolution: update the validator's properties without adding it to required. Existing documents simply don't have the field, and the validator passes them because the field is not required. No backfill is necessary. New documents can include the field; application code reads it with a safe fallback default.

// Add optional 'avatarUrl' field to the validator
db.runCommand({
  collMod: 'users',
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['name', 'email'],
      properties: {
        name:      { bsonType: 'string' },
        email:     { bsonType: 'string' },
        avatarUrl: { bsonType: 'string' }  // optional — no backfill needed
      }
    }
  }
});

Removing a Field From the Schema

To retire a field, first remove it from required if it was required, then deploy application code that no longer writes the field. Over time, new documents won't contain the field. You can optionally backfill by removing the field from all existing documents using $unset, but this is only necessary if the field wastes storage or causes confusion.

// Remove the deprecated 'legacyCode' field from all documents
db.products.updateMany(
  { legacyCode: { $exists: true } },
  { $unset: { legacyCode: '' } }
);

Zero-Downtime Migration Summary

The key insight for zero-downtime schema migration is that MongoDB allows mixed document shapes in the same collection. This means you never need to take the database offline to change the schema. The four-phase playbook—warn-mode validator, app code update, backfill, strict enforcement—decouples the schema change from the deployment and gives you full control over the transition timeline.

Verifying Migration Completeness

Before switching to strict mode, verify that zero documents are missing the required fields. A simple count query confirms completeness. If any documents are still non-conforming, run the backfill script again. This verification step prevents surprise validation errors after switching to error action.

// Verify no users are missing the new required field
const missing = await db.collection('users').countDocuments({
  phoneNumber: { $exists: false }
});
console.log('Documents missing phoneNumber:', missing);
// Should be 0 before enabling strict enforcement

Quick Check

Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.

Lesson Recap

In this lesson you learned: the four-phase migration playbook (warn → app update → backfill → strict) achieves zero downtime, the schema versioning pattern lets multiple document shapes coexist indefinitely, and verification before strict enforcement prevents surprise errors. Next up we explore projection and field selection to fetch only the fields your queries actually need.

เริ่มต้นได้ฟรี

เรียนรู้ JavaScript ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
30
บทเรียน
120

คำถามที่พบบ่อย

บทเรียน “การพัฒนาสคีมาโดยไม่หยุดให้บริการ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การพัฒนาสคีมาโดยไม่หยุดให้บริการ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส MongoDB Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การพัฒนาสคีมาโดยไม่หยุดให้บริการ”

ผู้เรียนจะอัปเดตตัวตรวจสอบที่มีอยู่ในคอลเลกชันที่กำลังใช้งานจริง และเขียนสคริปต์ย้ายข้อมูลเพื่อเติมเอกสารให้เป็นรูปแบบใหม่ คุณปฏิบัติ MongoDB Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน MongoDB Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน MongoDB Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การพัฒนาสคีมาโดยไม่หยุดให้บริการ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน MongoDB Academy นี้ได้ไหม

ได้ บทเรียน MongoDB Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การเพิ่มตัวตรวจสอบให้คอลเลกชัน
  2. ข้อจำกัดด้านชนิด ฟิลด์ที่จำเป็น และค่าที่ระบุไว้
  3. ระดับและการดำเนินการตรวจสอบ
  4. การพัฒนาสคีมาโดยไม่หยุดให้บริการ
← กลับไปที่ MongoDB Academy