Какие ORM для Node.js ты знаешь и использовал?

Ответ

В экосистеме Node.js я работал с несколькими ORM и ODM, выбор зависит от типа БД и стека проекта.

Для реляционных БД (PostgreSQL, MySQL, SQLite):

  1. Prisma — моя основная ORM для новых проектов. Она не является классической ORM, а скорее query builder с автоматической генерацией типов на основе схемы. Это даёт полную type-safe работу с БД прямо в TypeScript.

    // Схема в schema.prisma
    model User {
      id    Int     @id @default(autoincrement())
      email String  @unique
      name  String?
    }
    
    // Использование в коде
    const newUser = await prisma.user.create({
      data: { email: 'alex@example.com', name: 'Alex' },
    });
    // `newUser` имеет тип `User`, сгенерированный Prisma
  2. Sequelize — зрелая, многофункциональная ORM. Использовал её в legacy-проектах. Поддерживает множество диалектов SQL, но типизация в TypeScript может быть громоздкой.

    const User = sequelize.define('User', { name: DataTypes.STRING });
    const user = await User.findOne({ where: { id: 1 } });
  3. TypeORM — ORM, вдохновленная Hibernate и .NET Entity Framework. Мощная, но сложная. Хорошо подходит для больших enterprise-проектов с активным использованием декораторов.

    @Entity()
    export class User {
        @PrimaryGeneratedColumn() id: number;
        @Column() name: string;
    }
    const userRepo = connection.getRepository(User);
    await userRepo.save({ name: 'Alex' });

Для MongoDB:

  1. Mongoose (ODM) — де-факто стандарт для работы с MongoDB в Node.js. Предоставляет схему, валидацию, хуки и популяцию связей.
    const userSchema = new mongoose.Schema({ name: String, age: Number });
    const User = mongoose.model('User', userSchema);
    await User.create({ name: 'Alex', age: 30 });

Query Builder:

  1. Knex.js — не ORM, а мощный конструктор SQL-запросов. Часто используется в связке с Objection.js (легковесная ORM поверх Knex) или напрямую, когда нужен полный контроль над SQL.
    await knex('users').where('age', '>', 18).select('name');

Мой стек: Для новых проектов на TypeScript с PostgreSQL я выбираю Prisma из-за её безопасности типов и отличного DX. Для проектов на MongoDB — Mongoose. В микросервисах, где запросы простые, иногда обхожусь Knex.

Ответ 18+ 🔞

Ну вот, сидишь такой, выбираешь инструмент для базы данных, а там этих ORM — овердохуища, как говна за баней. Каждый второй фреймворк кричит, что он самый типобезопасный и удобный, а на деле половина — манда с ушами. Давай по порядку, без соплей.

Для нормальных, реляционных баз (PostgreSQL, MySQL и прочая):

  1. Prisma — это, блядь, моя основная любовь в последнее время. Это даже не совсем классическая ORM, а такой хитрожопый query builder, который на основе схемы тебе типы нагенерирует. Получается полная типобезопасность в TypeScript, и не нужно ебаться с этими интерфейсами вручную. Просто красота.

    // Описываешь схему в файле schema.prisma
    model User {
      id    Int     @id @default(autoincrement())
      email String  @unique
      name  String?
    }
    
    // А в коде просто берёшь и работаешь
    const newUser = await prisma.user.create({
      data: { email: 'alex@example.com', name: 'Alex' },
    });
    // И `newUser` уже автоматом имеет тип `User`. Никакого геморроя.
  2. Sequelize — это, ёпта, старый, матёрый кабан. Встречал его в куче легаси-проектов. Функциональности — хоть жопой ешь, кучу диалектов SQL поддерживает. Но если ты на TypeScript, приготовься к тому, что типизация там местами такая кривая, что хоть волком вой. Работает, но иногда хочется вилкой в глаз.

    const User = sequelize.define('User', { name: DataTypes.STRING });
    const user = await User.findOne({ where: { id: 1 } });
  3. TypeORM — мощная штука, вдохновлялась всякими Hibernate. Подходит для больших, навороченных проектов, где декораторы — это святое. Но, чувак, она сложная. Иногда такое чувство, что ты не базу данных конфигурируешь, а космический корабль запускаешь. Для enterprise — ок, для пет-проекта — терпения ноль ебать.

    @Entity()
    export class User {
        @PrimaryGeneratedColumn() id: number;
        @Column() name: string;
    }
    const userRepo = connection.getRepository(User);
    await userRepo.save({ name: 'Alex' });

Для MongoDB, где документы летают как хотят:

  1. Mongoose (ODM) — это, блядь, классика жанра. Если работаешь с Mongo, то это де-факто стандарт. Даёт тебе схему, валидацию, хуки — в общем, наводит хоть какой-то порядок в этом анархичном царстве JSON. Без него там вообще пидарас шерстяной получится.

    const userSchema = new mongoose.Schema({ name: String, age: Number });
    const User = mongoose.model('User', userSchema);
    await User.create({ name: 'Alex', age: 30 });

А иногда ORM — это перебор:

  1. Knex.js — это не ORM, а просто отличный конструктор SQL-запросов. Берёшь, когда нужно написать конкретный запрос и не хочется, чтобы ORM тебе там свою магию под капотом устраивала. Часто его используют с Objection.js или вообще без всяких обёрток. Контроль полный, как на механической коробке.

    await knex('users').where('age', '>', 18).select('name');

Итог, ёпта: Если делаю новый проект на TypeScript с PostgreSQL — мои руки сами тянутся к Prisma, потому что типы и удобство. Если проект на MongoDB — без вариантов, Mongoose. Ну а если пишешь какой-нибудь микросервис, где запросы простые, как три копейки, то иногда проще голым Knex отбиться, чем городить огород. Выбирай по задаче, а не потому что модно.