Работали ли вы с CRUD-операциями?

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

Ответ

Да, CRUD (Create, Read, Update, Delete) — это основа большинства API, которые я разрабатываю на Node.js. Обычно я реализую их с помощью Express.js и ORM, таких как Mongoose для MongoDB или Sequelize/TypeORM для PostgreSQL.

Пример CRUD для сущности Article с Express и Mongoose, включая валидацию и обработку ошибок:

const express = require('express');
const mongoose = require('mongoose');
const router = express.Router();

const ArticleSchema = new mongoose.Schema({
  title: { type: String, required: true, maxlength: 200 },
  content: { type: String, required: true },
  authorId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  publishedAt: { type: Date, default: Date.now }
});
const Article = mongoose.model('Article', ArticleSchema);

// CREATE
router.post('/', async (req, res, next) => {
  try {
    const article = new Article(req.body);
    await article.save();
    res.status(201).json(article);
  } catch (error) {
    next(error); // Ошибки валидации Mongoose будут обработаны middleware
  }
});

// READ (Paginated List)
router.get('/', async (req, res) => {
  const page = parseInt(req.query.page) || 1;
  const limit = parseInt(req.query.limit) || 10;
  const skip = (page - 1) * limit;

  const articles = await Article.find().skip(skip).limit(limit).populate('authorId', 'name');
  const total = await Article.countDocuments();
  res.json({ data: articles, page, totalPages: Math.ceil(total / limit) });
});

// UPDATE
router.patch('/:id', async (req, res, next) => {
  try {
    const article = await Article.findByIdAndUpdate(
      req.params.id,
      { $set: req.body },
      { new: true, runValidators: true } // `new:true` возвращает обновленный документ
    );
    if (!article) return res.status(404).json({ error: 'Article not found' });
    res.json(article);
  } catch (error) {
    next(error);
  }
});

// DELETE (Soft Delete)
router.delete('/:id', async (req, res) => {
  const article = await Article.findById(req.params.id);
  if (!article) return res.status(404).json({ error: 'Article not found' });
  article.deleted = true; // Помечаем как удаленное вместо физического удаления
  await article.save();
  res.status(204).send();
});

module.exports = router;

Важно дополнять базовый CRUD пагинацией, фильтрацией, популяцией связей, мягким удалением и строгой валидацией данных.