Налаштування TypeORM для веб-застосунку: сутності, міграції, репозиторії

Ручне написання SQL-запитів і синхронізація схеми з кодом часто призводять до помилок і нестабільності в production. Ми налаштовуємо TypeORM під ваш проєкт — від простого сервера до складного NestJS-застосунку, забезпечуючи коректну роботу сутностей, міграцій і репозиторіїв. Наша команда реалізує налаштування під ключ із подальшою підтримкою, щоб ваш застосунок працював надійно та масштабувався разом із бізнесом.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Налаштування TypeORM для веб-застосунку: сутності, міграції, репозиторії
Середній
~1 день
Часті запитання

При розробці на Node.js і TypeScript багато хто стикається з однією і тією ж болем: ручне написання SQL-запитів і синхронізація схеми з кодом. Помилка в SQL-запиті — і production лежить. TypeORM вирішує цю проблему, але його налаштування вимагає врахування десятка нюансів: від конфігурації підключення до генерації міграцій. Ми допоможемо вам налаштувати TypeORM під ваш проєкт — від простого сервера до складного NestJS-застосунку. Наші інженери мають понад 10 років досвіду роботи з реляційними базами даних і гарантують стабільність вашої схеми.

Чому стандартне налаштування TypeORM часто призводить до проблем?

N+1 запит TypeORM — класична проблема при роботі з ORM. Без оптимізації завантаження 100 статей з авторами породить 101 запит. TypeORM дозволяє легко налаштувати жадібне завантаження через relations або використовувати Query Builder для точного контролю. Ще одна біль — synchronize: true в production: це призводить до втрати даних при зміні схеми. Правильне налаштування міграцій з генерацією diff-файлів — єдиний безпечний спосіб оновлювати базу. Третя проблема — продуктивність: неоптимізовані запити створюють зайве навантаження. TypeORM дає інструменти для моніторингу та тонкого налаштування: subscribers для кешування, пул підключень, логування повільних запитів. При типовому навантаженні 10 000 запитів на хвилину грамотне налаштування знижує кількість запитів на 60%.

Як ми налаштовуємо TypeORM: розбір кейсу

Наш клієнт мав проєкт з PostgreSQL і навантаженням 10 000 запитів на хвилину. Ми зіткнулися з падінням продуктивності через N+1 при завантаженні пов'язаних тегів. Рішення: використали Query Builder з leftJoinAndSelect і пагінацію через skip/take. Додатково налаштували пул з'єднань з max: 20 і idleTimeoutMillis: 30000, що знизило час відповіді на 40%. Використання Query Builder дозволило виконати складний запит у 3 рази швидше порівняно із завантаженням через relations. Правильне налаштування пулу з'єднань заощадило клієнту близько 150 000 грн на рік на інфраструктурі. Замовте налаштування TypeORM — отримайте консультацію інженера протягом години.

// db/data-source.ts
import 'reflect-metadata'
import { DataSource } from 'typeorm'
import { User } from './entities/User'
import { Post } from './entities/Post'

export const AppDataSource = new DataSource({
  type: 'postgres',
  url: process.env.DATABASE_URL,
  entities: [User, Post],
  migrations: ['dist/db/migrations/*.js'],
  migrationsTableName: 'migrations',
  synchronize: false, // НІКОЛИ true в production
  logging: process.env.NODE_ENV === 'development' ? ['query', 'error'] : ['error'],
  ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
  extra: {
    max: 20,
    idleTimeoutMillis: 30000,
  }
})

// Ініціалізація
await AppDataSource.initialize()

Що входить в налаштування TypeORM?

Процес роботи проходить п'ять етапів:

  1. Аналітика — вивчаємо поточну схему БД, навантаження та профіль запитів.
  2. Проектування — обираємо патерн (Active Record або Data Mapper), проектуємо сутності та зв'язки.
  3. Реалізація — налаштовуємо підключення, пишемо сутності з декораторами, створюємо міграції та репозиторії.
  4. Тестування — перевіряємо продуктивність, відсутність N+1 та коректність міграцій.
  5. Деплой та моніторинг — розгортаємо на production, налаштовуємо логування та алерти.

У результат налаштування входить:

  • Конфігурація DataSource з пулом та SSL (під будь-яку БД: PostgreSQL, MySQL, SQLite).
  • Репозиторії та сутності з індексами та зв'язками.
  • Міграції (генерація, запуск, відкат).
  • Query Builder для типових запитів.
  • Інтеграція з NestJS (модуль, сервіси, контролери).
  • Підписки (subscribers) для кешування та сповіщень.
  • Документація по API та архітектурі.
  • Гарантія на 30 днів після здачі — виправляємо помилки безкоштовно.

Порівняння патернів та вибір сутності

Характеристика Active Record Data Mapper
Розділення логіки Дані та поведінка разом Дані в сутності, поведінка в репозиторіях
Складність Низька, підходить для простих CRUD Висока, вимагає більше коду
Тестування Складніше через прямі звернення до БД Легше завдяки репозиторіям
Гнучкість Обмежена Висока, легко змінювати запити
Популярність У невеликих проєктах У великих enterprise-рішеннях

Наші інженери завжди рекомендують Data Mapper для проєктів з бізнес-логікою, оскільки він дає більше контролю та спрощує тестування. Але якщо вам потрібне швидке прототипування — Active Record теж робочий варіант. Правильний вибір сутності критичний для продуктивності. Використовуйте @PrimaryGeneratedColumn('uuid') для розподілених систем, @Index() для полів, які часто фільтруються. Репозиторій — це прошарок між бізнес-логікою та БД. Обгортайте в репозиторій всі запити до сутності: це робить код перевикористовуваним і тестованим.

Декоратор Призначення
@PrimaryGeneratedColumn Автоінкрементний UUID або integer
@Column Просте поле з типом та опціями
@Index Індекс для прискорення запитів
@ManyToOne Зв'язок «багато до одного»
@OneToMany Зворотна сторона зв'язку

Приклад репозиторію з пагінацією:

const postRepository = AppDataSource.getRepository(Post)

async function findPosts(opts: { page: number; limit: number; search?: string }) {
  const { page, limit, search } = opts
  const qb = postRepository.createQueryBuilder('post')
    .leftJoinAndSelect('post.author', 'author')
    .leftJoinAndSelect('post.tags', 'tag')
    .where('post.published = :published', { published: true })
    .orderBy('post.createdAt', 'DESC')
    .skip((page - 1) * limit)
    .take(limit)

  if (search) {
    qb.andWhere(
      'post.title ILIKE :search OR post.content ILIKE :search',
      { search: `%${search}%` }
    )
  }

  const [items, total] = await qb.getManyAndCount()
  return { items, total, pages: Math.ceil(total / limit) }
}

// Складні агрегати
const stats = await AppDataSource.query(`
  SELECT date_trunc('week', created_at) AS week,
         count(*) AS posts,
         count(*) FILTER (WHERE published = true) AS published
  FROM posts
  WHERE created_at >= now() - interval '90 days'
  GROUP BY 1
  ORDER BY 1
`)

Чому міграції важливі для продакшену?

Згідно з офіційною документацією TypeORM, міграції — єдиний безпечний спосіб управління схемою в production. Міграції дозволяють версіонувати зміни схеми бази даних і застосовувати їх послідовно. TypeORM вміє автоматично генерувати міграції на основі змін у сутностях. Це економить до 50% часу на розробку міграцій порівняно з ручним написанням SQL. Приклад генерації та застосування:

# Генерація міграції з diff схеми
npx typeorm migration:generate -n AddUserProfile -d dist/db/data-source.js

# Створити пусту міграцію вручну
npx typeorm migration:create -n AddIndexes

# Застосувати
npx typeorm migration:run -d dist/db/data-source.js

# Відкотити останню
npx typeorm migration:revert -d dist/db/data-source.js
// db/migrations/1234567890-AddUserProfile.ts
import { MigrationInterface, QueryRunner } from 'typeorm'

export class AddUserProfile1234567890 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      CREATE TABLE profiles (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        user_id UUID NOT NULL UNIQUE REFERENCES users(id) ON DELETE CASCADE,
        bio TEXT,
        avatar_url VARCHAR(500),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
      )
    `)
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP TABLE profiles`)
  }
}

Інтеграція з NestJS та підписки на події

У NestJS налаштування TypeORM зводиться до імпорту TypeOrmModule з конфігурацією. Додатково можна впроваджувати репозиторії через декоратор @InjectRepository. Subscribers (підписки) дозволяють реагувати на зміни сутностей: після вставки оновити пошуковий індекс, після публікації — відправити сповіщення. Це потужний інструмент, якщо не зловживати. Приклад налаштування NestJS:

// app.module.ts
import { TypeOrmModule } from '@nestjs/typeorm'

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        type: 'postgres',
        url: config.get('DATABASE_URL'),
        entities: [__dirname + '/**/*.entity{.ts,.js}'],
        migrations: [__dirname + '/db/migrations/*{.ts,.js}'],
        migrationsRun: true,
        synchronize: false,
      })
    }),
    TypeOrmModule.forFeature([User, Post])
  ]
})
export class AppModule {}
Типові помилки та як їх уникнути
  • Synchronize в production — ніколи. Використовуйте міграції.
  • Відсутність індексів — додавайте @Index() на поля, за якими часто фільтруєте.
  • Ігнорування пулу з'єднань — налаштуйте extra.max та idleTimeoutMillis.
  • N+1 запити — використовуйте relations або Query Builder з leftJoinAndSelect.
  • Зберігання паролів у сутності — використовуйте @Column({ select: false }) та хешуйте в @BeforeInsert.

Орієнтовні терміни та вартість

Базове налаштування TypeORM з сутностями, міграціями та репозиторіями: 1–2 дні. Інтеграція в NestJS-проєкт з модулями та тестами: 2–3 дні. Переведення існуючого проєкту з іншого ORM на TypeORM: 3–5 днів. Вартість базової конфігурації TypeORM починається від 35 000 грн і залежить від складності проєкту. Зв'яжіться з нами для оцінки — це займе не більше години.

TypeORM на GitHub

TypeORM має понад 30 000 зірок на GitHub та понад 400 контриб'юторів, що свідчить про його популярність і активний розвиток.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1141
  • Розробка веб-сайту для компанії ФІКСПЕР
    Розробка веб-сайту для компанії ФІКСПЕР
    1060