Что такое сиды (Seeds) в контексте баз данных и Node.js?

Ответ

Сиды (Seeds) — это скрипты для заполнения базы данных предопределёнными (начальными) данными. В Node.js-проектах они используются вместе с миграциями для приведения базы данных в предсказуемое состояние, необходимое для работы приложения.

Зачем они нужны в Node.js проекте?

  1. Наполнение справочными данными: Роли пользователей (admin, user), типы подписок, список стран, категории товаров.
  2. Создание тестовых данных: Для разработки, демо-стендов или наполнения staging-окружения.
  3. Добавление обязательных записей: Учётная запись супер-администратора, настройки по умолчанию.

Пример сида с использованием Knex.js (популярный SQL query builder для Node.js):

// seeds/01_initial_roles.js
exports.seed = async function(knex) {
  // Deletes ALL existing entries
  await knex('user_roles').del();

  // Inserts seed entries
  return knex('user_roles').insert([
    { id: 1, name: 'admin', description: 'Full system access' },
    { id: 2, name: 'moderator', description: 'Can manage content' },
    { id: 3, name: 'user', description: 'Regular user' },
  ]);
};

Запуск: npx knex seed:run

Пример сида для создания тестового пользователя с хешированным паролом (используя bcrypt):

// seeds/02_demo_users.js
const bcrypt = require('bcrypt');

exports.seed = async function(knex) {
  const saltRounds = 10;
  const hashedPassword = await bcrypt.hash('demo123', saltRounds);

  return knex('users').insert([
    {
      email: 'admin@example.com',
      password_hash: hashedPassword,
      role_id: 1, // Ссылается на роль 'admin' из предыдущего сида
      is_active: true,
      created_at: knex.fn.now()
    }
  ]);
};

Best Practices в Node.js:

  • Идемпотентность: Сиды должны безопасно выполняться многократно. Часто начинаются с очистки таблиц (del() или truncate()).
  • Порядок выполнения: Важен из-за внешних ключей. Сиды для справочных таблиц (роли) должны выполняться перед сидами, которые на них ссылаются (пользователи).
  • Не для продакшена: Как правило, сиды с тестовыми данными не запускаются на production. Для обязательных справочных данных иногда используют миграции или отдельные скрипты деплоя.
  • Использование с ORM: Аналогичная логика работает с Sequelize, TypeORM и другими библиотеками.

Ответ 18+ 🔞

А, сиды, говоришь? Ну это, блядь, такая штука, чтобы базу данных не как пустую консервную банку оставлять, а сразу чем-то полезным набить. Представь, ты приложение собрал, а там ролей нет, админа нет — нихуя не работает. Вот сиды как раз этот пиздец и предотвращают.

Зачем они вообще нужны, этот огород городить?

  1. Справочники набить. Ну там, admin, user, moderator — базовые роли, без которых нихуя не сдвинется. Или список стран, категорий товаров — всё это надо сразу в базу запихнуть, а не руками потом тыкать.
  2. Тестовый мусор создать. Для разработки, чтобы не на пустой базе сидеть и глаза мозолить. Сделал сид — и у тебя сразу сто юзеров, тысяча товаров. Красота.
  3. Обязательную хуйню добавить. Самый главный кейс — создать учётку супер-админа, чтобы зайти и всё настроить. Без этого — пиши пропало, доступ к своему же приложению потеряешь, ядрёна вошь.

Смотри, как это выглядит на практике (Knex.js):

// seeds/01_initial_roles.js
exports.seed = async function(knex) {
  // Сначала всю старую хуйню нахуй выкидываем. Идемпотентность, ёпта!
  await knex('user_roles').del();

  // А теперь свеженькое засовываем
  return knex('user_roles').insert([
    { id: 1, name: 'admin', description: 'Полный доступ, царь и бог' },
    { id: 2, name: 'moderator', description: 'Может контентом рулить' },
    { id: 3, name: 'user', description: 'Обычный юзер, как все мы' },
  ]);
};

Запускается просто: npx knex seed:run — и поехали.

А вот пример посерьёзнее, с паролем (bcrypt в помощь):

// seeds/02_demo_users.js
const bcrypt = require('bcrypt');

exports.seed = async function(knex) {
  const saltRounds = 10;
  // Пароль хешируем, а то какой же админ с паролем '12345'? Пизда рулю.
  const hashedPassword = await bcrypt.hash('demo123', saltRounds);

  return knex('users').insert([
    {
      email: 'admin@example.com',
      password_hash: hashedPassword,
      role_id: 1, // Это ссылка на роль 'admin' из прошлого сида
      is_active: true,
      created_at: knex.fn.now()
    }
  ]);
};

Важные моменты, чтобы не обосраться:

  • Идемпотентность — святое. Сид должен работать так, чтобы его можно было хоть сто раз запустить, и будет один и тот же результат. Поэтому обычно начинают с удаления старых данных.
  • Порядок — всё. Сначала создаём роли, потом юзеров, которые на эти роли ссылаются. Иначе будет ошибка внешнего ключа, и ты будешь сидеть и думать, какого хуя.
  • На продакшн — осторожно. Тестовых юзеров с паролем qwerty на боевой сервер пихать — идея пиздопроебибна. Справочники — можно, мусор — ни в коем случае.
  • С ORM — та же фигня. С Sequelize, TypeORM логика абсолютно такая же, просто синтаксис другой. Суть одна: накатить в базу начальные данные и не ебать себе мозги.