MongoDB Academy · Урок

Изменение схем без простоя

Вы обновите существующий валидатор в рабочей коллекции и напишете скрипты миграции для приведения документов к новой структуре.

Урок 4 из 413 шагов

«Изменение схем без простоя» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Добавление валидатора в коллекцию
  2. Ограничения типов, обязательности и перечислений
  3. Уровни и действия проверки
  4. Изменение схем без простоя
← Назад к MongoDB Academy