Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Seeds (Семена) в базах данных
Seeds — это исходные данные, которые загружаются в базу данных при инициализации или при настройке development окружения. Это не тестовые данные, а необходимый минимум для работы приложения.
Что такое Seeds?
Seeds (семена) — это скрипты, которые заполняют БД начальными данными:
- Справочные данные (категории, статусы, роли)
- Демо-данные для development
- Конфигурационные параметры
- Тестовые пользователи
- Константы приложения
Аналогия: если миграция создает структуру, то seed наполняет ее смыслом.
Зачем нужны Seeds?
1. Development окружение
Всем разработчикам нужны одинаковые тестовые данные для работы:
# Вместо того, чтобы каждый вручную создавал:
# - категории товаров
# - тестовых пользователей
# - справочные данные
# Делаем один раз:
npm run seed
2. Миграция между окружениями
При развертывании на production нужны базовые данные (роли, статусы):
# На production после миграции
docker exec app npm run seed:prod
3. Тестирование
Тесты требуют известное состояние БД:
beforeEach(async () => {
// Seed test database
await seedTestData();
});
test('должен найти пользователя', async () => {
// У нас уже есть тестовые данные
const user = await userService.findById('test-user-id');
expect(user).toBeDefined();
});
4. Демонстрация и прототипирование
Для клиентов и стейкхолдеров нужен реалистичный данные:
# Запускаем demo версию с красивыми данными
npm run seed:demo
npm run dev
Примеры Seeds
Пример 1: Справочные данные (Knex seeder)
// seeds/001_insert_roles.ts
export async function seed(knex: Knex): Promise<void> {
// Удаляем существующие роли
await knex('roles').del();
// Вставляем базовые роли
await knex('roles').insert([
{
id: 1,
name: 'admin',
description: 'Administrator role',
created_at: new Date(),
},
{
id: 2,
name: 'user',
description: 'Regular user role',
created_at: new Date(),
},
{
id: 3,
name: 'moderator',
description: 'Moderator role',
created_at: new Date(),
},
]);
}
Пример 2: Тестовые пользователи (TypeORM seeder)
// src/database/seeds/user.seeder.ts
import { DataSource } from 'typeorm';
import { User } from '../entities/User';
import * as bcrypt from 'bcrypt';
export async function seedUsers(dataSource: DataSource): Promise<void> {
const userRepository = dataSource.getRepository(User);
const users = [
{
email: 'admin@example.com',
password: await bcrypt.hash('admin123', 10),
role: 'admin',
name: 'Admin User',
},
{
email: 'user@example.com',
password: await bcrypt.hash('user123', 10),
role: 'user',
name: 'Test User',
},
];
// Проверяем, что пользователи еще не существуют
for (const userData of users) {
const exists = await userRepository.findOne({
where: { email: userData.email },
});
if (!exists) {
await userRepository.save(userData);
}
}
}
Пример 3: Категории товаров
// seeds/categories.ts
export async function seed(dataSource: DataSource) {
const categoryRepo = dataSource.getRepository(Category);
const categories = [
{ name: 'Electronics', slug: 'electronics' },
{ name: 'Books', slug: 'books' },
{ name: 'Clothing', slug: 'clothing' },
{ name: 'Food', slug: 'food' },
];
for (const cat of categories) {
await categoryRepo.save({
...cat,
createdAt: new Date(),
});
}
}
Пример 4: Комплексный seed с связями
// seeds/populate-store.ts
export async function seed(dataSource: DataSource) {
const userRepo = dataSource.getRepository(User);
const productRepo = dataSource.getRepository(Product);
const orderRepo = dataSource.getRepository(Order);
// 1. Создаем пользователя
const user = await userRepo.save({
email: 'customer@example.com',
name: 'John Doe',
});
// 2. Создаем товары
const products = await productRepo.save([
{ name: 'Laptop', price: 999.99 },
{ name: 'Phone', price: 599.99 },
{ name: 'Headphones', price: 199.99 },
]);
// 3. Создаем заказы
await orderRepo.save({
user,
products: [products[0]],
total: 999.99,
status: 'completed',
});
}
Seeds vs Migrations
Миграции (Migrations):
-- up: создаёт таблицу
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255)
);
-- down: удаляет таблицу
DROP TABLE users;
Seeds:
// Вставляет данные после создания таблицы
await userRepository.insert({
email: 'test@example.com'
});
Ключевое различие:
- Миграция — это структура (CREATE, ALTER, DROP)
- Seed — это содержимое (INSERT, UPDATE)
Лучшие практики Seeds
1. Идемпотентность (Idempotency)
Seed должен работать много раз без ошибок:
// Правильно: проверяем существование
const exists = await roleRepo.findOne({ where: { name: 'admin' } });
if (!exists) {
await roleRepo.save({ name: 'admin' });
}
// Неправильно: просто вставляем (вызовет ошибку при повторном запуске)
await roleRepo.save({ name: 'admin' });
2. Разные seeds для разных окружений
// seeds/development.seed.ts — много demo данных
export async function seed() {
await seedCategories();
await seedManyProducts(1000);
await seedTestUsers(100);
}
// seeds/production.seed.ts — только критичное
export async function seed() {
await seedRoles();
await seedCountries();
}
3. Семена должны быть воспроизводимы
// Правильно: определенные данные
const categories = [
{ id: 1, name: 'Electronics' },
{ id: 2, name: 'Books' },
];
// Неправильно: случайные данные
const name = Math.random().toString();
4. Документирование
/**
* Seeds для development окружения
*
* Создает:
* - Admin user (email: admin@example.com, password: admin123)
* - 3 обычных пользователя
* - 5 категорий товаров
* - 50 тестовых товаров
*/
export async function seed() {
// ...
}
Seeds в Node.js фреймворках
Express/Fastify с Knex:
npm install knex
npx knex seed:make create_initial_data
npm run knex:seed
TypeORM:
npm run typeorm migration:run
npm run seed # Custom seed runner
Prisma:
// prisma/seed.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
// Seed data
}
main()
.catch(e => process.exit(1))
.finally(() => prisma.$disconnect());
// package.json
{
"prisma": {
"seed": "ts-node prisma/seed.ts"
}
}
pprisma db seed
Workflow в команде
1. Разработчик создает миграцию
npm run migration:create add_categories_table
2. Разработчик создает seed
npm run seed:create populate_categories
3. Другие разработчики затягивают оба
git pull
npm run migration:run
npm run seed
4. На production (DevOps)
# After deployment
docker exec app npm run migration:run
docker exec app npm run seed:prod
Заключение
Seeds — это критичный инструмент для:
- Консистентности окружений
- Автоматизации setup
- Тестирования
- Демонстрации
Хороший seed спасает часы разработки и предотвращает ошибки, связанные с различиями в данных между разработчиками.