Изменение схем без простоя
Вы обновите существующий валидатор в рабочей коллекции и напишете скрипты миграции для приведения документов к новой структуре.
«Изменение схем без простоя» — бесплатный урок MongoDB Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения MongoDB Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс MongoDB Academy содержит 4 уроков всего.
Сложности изменения схемы
По мере роста приложения требования меняются, и схема MongoDB должна развиваться. В отличие от реляционных баз данных, вы не можете выполнить блокирующую операцию ALTER TABLE, которая блокирует всю таблицу на время миграции. Гибкость MongoDB означает, что старые и новые формы документов могут сосуществовать в одной коллекции, поэтому для сохранения работоспособности приложения во время перехода схемы требуется продуманная стратегия миграции.
Шаг 1. Обновите валидатор в режиме предупреждений
Начинайте каждую миграцию схемы с обновления валидатора коллекции в соответствии с новой схемой, но установите validationAction: 'warn'. Это позволяет сохранять и обновлять существующие несоответствующие документы без ошибок, пока вы подсчитываете, сколько документов нужно дополнительно заполнить. Новые записи из обновлённого кода приложения будут соответствовать новой схеме.
// 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'
});Шаг 2. Обновите код приложения
Разверните обновлённый код приложения, который записывает документы в соответствии с новой схемой. Новые документы теперь будут содержать новые поля. Старые документы, записанные до изменения схемы, останутся в коллекции в исходной форме. На этом этапе код приложения должен обрабатывать обе формы документов — например, подставляя значение по умолчанию, если новое поле отсутствует.
// 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';
}Шаг 3. Напишите скрипт миграции для заполнения данных
Скрипт заполнения перебирает все документы, в которых отсутствует новое поле, и устанавливает значение по умолчанию. Запускайте его небольшими пакетами, чтобы не блокировать ресурсы и не создавать резких всплесков нагрузки на сервер. Для повышения эффективности используйте bulkWrite с параметром ordered: false, а ход выполнения отслеживайте с помощью журналирования, чтобы продолжить работу после прерывания.
// 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');Шаг 4. Переключитесь в строгий режим ошибок
После завершения заполнения и проверки соответствия всех документов новой схеме установите для validationLevel значение strict, а для validationAction — error. С этого момента любая запись, нарушающая схему, будет отклоняться. В первые часы после переключения отслеживайте приложение на наличие неожиданных ошибок, чтобы обнаружить крайние случаи, которые не были учтены при заполнении.
// Enable full enforcement after backfill is verified
db.runCommand({
collMod: 'users',
validationLevel: 'strict',
validationAction: 'error'
});
console.log('Full schema enforcement enabled');Безопасное переименование поля
Чтобы переименовать поле (например, fullName → name), сначала добавляйте name в новые документы, пока приложение по-прежнему читает fullName как резервное значение. Затем заполните данные, скопировав fullName в name с помощью $rename или $set. Наконец, обновите приложение, чтобы оно записывало и читало только name, и удалите fullName из старых документов.
// Backfill: rename fullName to name for all existing documents
db.users.updateMany(
{ fullName: { $exists: true }, name: { $exists: false } },
[{ $set: { name: '$fullName' } }, { $unset: 'fullName' }]
);Шаблон версионирования схемы
Для сложных длительных миграций добавьте поле schemaVersion в каждый документ. Код приложения проверяет это поле и применяет функцию преобразования для каждой старой версии перед обработкой документа. Новые записи всегда содержат последнюю версию schemaVersion. Это обеспечивает контролируемый и проверяемый путь обновления и позволяет нескольким поколениям схем бессрочно сосуществовать.
// 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;
}Безопасное добавление нового необязательного поля
Добавление нового необязательного поля — самый простой вариант развития схемы: обновите properties валидатора, не добавляя это поле в required. В существующих документах просто не будет этого поля, и валидатор пропустит их, поскольку поле не является обязательным. Заполнять старые документы не нужно. Новые документы могут содержать это поле, а код приложения читает его, используя безопасное значение по умолчанию.
// 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
}
}
}
});Удаление поля из схемы
Чтобы вывести поле из употребления, сначала удалите его из required, если оно было обязательным, а затем разверните код приложения, который больше не записывает это поле. Со временем новые документы не будут содержать его. При необходимости можно удалить поле из всех существующих документов с помощью $unset, но это нужно только в том случае, если поле занимает место или вызывает путаницу.
// Remove the deprecated 'legacyCode' field from all documents
db.products.updateMany(
{ legacyCode: { $exists: true } },
{ $unset: { legacyCode: '' } }
);Итоги миграции без простоя
Главная идея миграции схемы без простоя заключается в том, что MongoDB позволяет документам разной формы находиться в одной коллекции. Поэтому для изменения схемы не требуется отключать базу данных. План из четырёх этапов — валидатор в режиме предупреждений, обновление кода приложения, заполнение данных, строгая проверка — отделяет изменение схемы от развёртывания и даёт полный контроль над сроками перехода.
Проверка завершённости миграции
Перед переключением в строгий режим убедитесь, что ни в одном документе не отсутствуют обязательные поля. Простой запрос подсчёта подтвердит завершённость операции. Если какие-либо документы всё ещё не соответствуют схеме, снова запустите скрипт заполнения. Этот этап проверки предотвращает неожиданные ошибки проверки после переключения действия на error.
// 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Быстрая проверка
Проверьте, насколько хорошо вы поняли концепции MongoDB и баз данных NoSQL из этого урока.
Итоги урока
В этом уроке вы узнали, что план миграции из четырёх этапов (предупреждения → обновление приложения → заполнение данных → строгий режим) обеспечивает работу без простоя, шаблон версионирования схемы позволяет нескольким формам документов бессрочно сосуществовать, а проверка перед включением строгого режима предотвращает неожиданные ошибки. Далее мы рассмотрим проекцию и выбор полей, чтобы получать только те поля, которые действительно нужны вашим запросам.
Изучай JavaScript с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 30
- Уроки
- 120
Часто задаваемые вопросы
Урок «Изменение схем без простоя» бесплатный?
Да — полный текст урока «Изменение схем без простоя» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс MongoDB Academy, подпишись на CoddyKit PRO. Курс MongoDB Academy содержит 4 уроков всего.
Чему я научусь в уроке «Изменение схем без простоя»?
Вы обновите существующий валидатор в рабочей коллекции и напишете скрипты миграции для приведения документов к новой структуре. Ты практикуешь MongoDB Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать MongoDB Academy?
Предыдущий опыт не требуется. MongoDB Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Изменение схем без простоя»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке MongoDB Academy?
Да. Каждый урок MongoDB Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Добавление валидатора в коллекцию
- Ограничения типов, обязательности и перечислений
- Уровни и действия проверки
- Изменение схем без простоя