Принимал ли ты решение о выборе базы данных для Node.js проекта

«Принимал ли ты решение о выборе базы данных для Node.js проекта» — вопрос из категории Архитектура, который задают на 26% собеседований Node.js Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, на проекте электронной коммерции я отвечал за выбор базы данных. Мы рассматривали три варианта для Node.js стека:

1. PostgreSQL — выбрали для основного каталога товаров и заказов:

// Структура заказа с транзакциями
await client.query('BEGIN');
try {
  // 1. Создаем заказ
  const orderResult = await client.query(
    `INSERT INTO orders (user_id, total, status) 
     VALUES ($1, $2, 'pending') RETURNING id`,
    [userId, total]
  );

  // 2. Добавляем товары в заказ
  for (const item of items) {
    await client.query(
      `INSERT INTO order_items (order_id, product_id, quantity, price)
       VALUES ($1, $2, $3, $4)`,
      [orderResult.rows[0].id, item.productId, item.quantity, item.price]
    );
  }

  await client.query('COMMIT');
} catch (error) {
  await client.query('ROLLBACK');
  throw error;
}

Почему PostgreSQL:

  • ACID-транзакции — критично для финансовых операций
  • JSONB — хранили метаданные товаров как JSON, но с индексацией
  • Сложные JOIN — для аналитических отчетов по продажам
  • PostGIS — рассчитывали доставку по геолокации

2. MongoDB — использовали для пользовательских сессий и логов:

// Гибкая схема для логов
const sessionSchema = new mongoose.Schema({
  userId: mongoose.ObjectId,
  deviceInfo: { type: Map, of: String },
  actions: [{
    type: String,
    timestamp: Date,
    metadata: { type: Map, of: mongoose.Schema.Types.Mixed }
  }],
  expiresAt: { type: Date, expires: 604800 } // TTL 7 дней
});

Почему MongoDB:

  • Быстрая запись — до 10k событий в секунду
  • Гибкая схема — добавляли новые поля без миграций
  • Агрегации — для анализа пользовательского поведения
  • TTL индексы — автоматическая очистка старых данных

3. Redis — для кэширования и очередей:

// Кэширование популярных товаров
const cacheKey = `popular:products:${categoryId}`;
const cached = await redis.get(cacheKey);

if (cached) {
  return JSON.parse(cached);
}

const products = await Product.find({ categoryId }).limit(20);
await redis.setex(cacheKey, 300, JSON.stringify(products)); // 5 минут

Критерии выбора:

  1. Согласованность данных — PostgreSQL для финансовых данных
  2. Производительность — Redis для горячих данных, MongoDB для логов
  3. Масштабирование — горизонтальное для MongoDB, вертикальное для PostgreSQL
  4. Экосистема — драйверы pg, mongoose, ioredis отлично работают с Node.js

В итоге использовали полиглотное хранилище: PostgreSQL как source of truth, MongoDB для операционных данных, Redis для кэша.