Không chạy một lệnh updateMany trên toàn bộ collection — nó giữ lock theo lô, làm oplog nở đột ngột và replication lag tăng. Cách làm là schema versioning + backfill dần.
Bước 1 — code đọc chịu được cả hai dạng. Deploy trước khi động vào dữ liệu:
const tier = doc.tier ?? deriveTier(doc.totalSpent) // fallback cho document cũGắn kèm field schemaVersion vào document để biết dạng nào là dạng nào.
Bước 2 — ghi theo dạng mới. Mọi write từ lúc này đều tạo document schemaVersion: 2, nên tập document cũ chỉ giảm chứ không tăng.
Bước 3 — backfill theo lô, có nhịp nghỉ.
let lastId = null
while (true) {
const filter = { schemaVersion: { $ne: 2 }, ...(lastId ? { _id: { $gt: lastId } } : {}) }
const batch = await coll.find(filter).sort({ _id: 1 }).limit(1000).toArray()
if (!batch.length) break
await coll.bulkWrite(batch.map(toUpdateOp), { ordered: false })
lastId = batch.at(-1)._id
await sleep(200) // give replication room to catch up
}Phân trang theo _id thay vì skip (skip vẫn phải duyệt qua phần bị bỏ). Theo dõi replication lag trong lúc chạy, thấy lag tăng thì giãn nhịp hoặc giảm cỡ lô.
Bước 4 — dọn. Khi đếm được số document schemaVersion: 1 bằng 0, gỡ nhánh fallback trong code và có thể bật schema validation strict.
Trình tự này giữ đúng nguyên tắc đọc trước, ghi sau, dọn cuối, nhờ đó rollback ở bất kỳ bước nào cũng không làm hỏng dữ liệu.