Course contentsShow
← Databases & SQL
Lesson 1258 of 1,95311. NoSQL and Document ModelsFree lesson

Document Migration Scripts

Write reliable, non-blocking scripts to update document structures in production.

In this lesson, you will learn how to design non-blocking migration scripts that safely evolve document schemas without locking your production environment.

The Challenge of Schema Evolution

When working with document databases, you often reach a point where you need to restructure your data—perhaps renaming a field, moving it into a nested object, or calculating a new value for every record. If you run a script that iterates through millions of documents and updates them in one go, you risk long-running write locks, exhausted transaction logs, and increased latency for your end users.

The Non-Blocking Pattern

Instead of a "big bang" update, we use a batch-processing migration pattern. The strategy involves three core components: batching, pausing, and idempotency.

1. Controlled Batching

Process your data in small, manageable chunks (e.g., 100–500 documents at a time). This keeps the load on your database consistent and allows your application to handle other operations between batches.

2. Idempotency

Ensure your script can be run multiple times safely. Use a version flag or a specific check to verify if a document has already been updated. If the script crashes, you can simply restart it, and it will skip the documents that were already migrated.

3. Concrete Example

In a standard document database, your migration script logic should look roughly like this:

// Migration: Rename 'user_name' to 'display_name'
const batchSize = 100;
let cursor = db.collection('users').find({ display_name: { $exists: false } }).limit(batchSize);

while (cursor.hasNext()) {
    let doc = cursor.next();
    
    // Perform the update only if it hasn't been migrated
    db.collection('users').updateOne(
        { _id: doc._id, display_name: { $exists: false } },
        { 
            $set: { display_name: doc.user_name },
            $unset: { user_name: "" } 
        }
    );
    
    // Small sleep/pause to allow index updates and thread recovery
    sleep(50); 
}

By filtering for documents that haven't been updated yet ({ display_name: { $exists: false } }), you ensure that your script is idempotent. By limiting the batch size and adding a brief sleep interval, you prevent the migration from monopolizing database resources, keeping the system responsive for active users.

Key Takeaway: Migrate production documents using idempotent batch processes to prevent performance degradation and allow for safe, resumable schema evolution.