Хуки Mongoose  —  своего рода ниндзя-шпионы, работающие вне поля зрения, перехватывая и изменяя операции с данными в ключевых точках. Это невероятно мощные инструменты для добавления пользовательской логики в Mongoose-приложения, но их освоение может быть похоже на взлом секретного кода. Но вам, бесстрашные разработчики, незачем волноваться, ведь эта статья упростит задачу.

Что такое хуки Mongoose?

Хуки  —  это промежуточные функции, срабатывающие в определенные моменты жизненного цикла Mongoose. Считайте их контрольными точками, позволяющими проверять, изменять или даже прерывать такие операции, как сохранение, обновление или удаление документов. Они бывают двух видов:

  • Pre-hooks (предварительные хуки): запускаются перед основной операцией, позволяя манипулировать данными или выполнять валидацию до попадания в базу данных.
  • Post-hooks (послеоперационные хуки): запускаются после выполнения основной операции, позволяя реагировать на результат (успех или неудачу) и выполнять такие задачи, как отправка уведомлений или регистрация изменений.

Типы хуков Mongoose

Mongoose предлагает четыре типа хуков, каждый из которых отвечает различным потребностям.

  • Хуки для документов: предназначены для отдельных документов и работают с такими методами, как save, update и remove.
  • Хуки для запросов: перехватывают и изменяют запросы до того, как они попадают в базу данных. Полезны для добавления предварительных условий или установки ограничений.
  • Хуки для агрегирования: подключаются к конвейеру агрегирования, позволяя изменять преобразования данных во время процесса агрегирования.
  • Хуки для моделей: запускаются для всей модели. Полезны для глобальных задач, таких как установка временных меток и инициализация значений по умолчанию.

Преимущества использования хуков Mongoose

Вот основные преимущества применения хуков.

  • Инкапсулированная логика. Переносите сложную логику из схем моделей в многократно используемые хуки, сохраняя чистоту и удобство обслуживания кода.
  • Валидация и безопасность. Выполняйте пользовательские валидации и преобразования данных до того, как они попадут в базу данных, повышая целостность и безопасность данных.
  • Автоматизация и уведомления. Запускайте автоматизированные задачи, такие как отправка электронных писем и регистрация изменений на основе операций с данными.
  • Расширяемость и плагины. Создавайте многократно используемые плагины на основе хуков для совместного использования функциональности в приложениях.

Хуки в действии

Посмотрим несколько примеров кода, чтобы понять, как работают хуки.

Хук предварительной проверки перед сохранением для хэширования паролей (pre-save hook)

const userSchema = new Schema({
username: String,
password: String,
});

// хук предварительной проверки
userSchema.pre('save', async function (next) {
if (!this.isModified('password')) return next();
const hashedPassword = await bcrypt.hash(this.password, 10);
this.password = hashedPassword;
next();
});

Этот хук проверяет, не изменен ли пароль. Если да, то перед сохранением документа хэширует его с помощью bcrypt.

Хук для отправки уведомлений об удалении после операции удаления (post-remove hook)

const userSchema = new Schema({
email: String,
});

userSchema.post('remove', function (user) {
// Отправка email-уведомления об удаленном пользователе
sendEmail(user.email, 'Your account has been deleted');
});

Этот хук отправляет уведомление по электронной почте, когда документ пользователя удаляется.

Примеры для Next.js

Хук post-find для преобразования _id в строку 

const userSchema = new Schema({
// ... другие поля
});

// вместо 'find' можем также использовать regex
userSchema.post('find', function (docs) {
for (const doc of docs) {
doc._id = doc._id.toString();
}
});

Маршрут API (для Next 12 и более ранних версий)

import User from '../../models/user';

export default async function handler(req, res) {
const users = await User.find();
res.json(users);
}

Маршрут API (для Next 13 и более поздних версий)

import User from '../../models/user';

export async function GET() {
const users = await User.find();
return new Response(
JSON.stringify(users);
)
}

Компонент (app/page.tsx)

import React from 'react';

export default function Page() {
const { data } = useSWR('/api/page', fetcher); // Fetch data using SWR
return (
<ul>
{data?.map((user) => (
<li key={user._id}>{user.name} (ID: {user._id})</li>
))}
</ul>
);
}

Ключевые моменты

Из приведенных примеров можно сделать следующие выводы:

  • Хук post('find') изменяет все документы, возвращаемые User.find().
  • Он преобразует свойство _id из ObjectId в строку, что делает его совместимым с компонентами Next.js 13.
  • Маршруты API обеспечивают получение данных на стороне сервера, где выполняются хуки Mongoose.
  • SWR (или любая другая библиотека, помогающая извлекать данные) используется для получения и кэширования данных в компоненте.

Дополнительные соображения

При использовании хуков учитывайте следующие моменты.

  • Если нужно изменить отдельные документы перед передачей их компонентам, рассмотрите возможность использования хука предварительного поиска (pre-find hook) или промежуточного программного обеспечения.
  • Для сложных преобразований или фильтрации данных можно использовать хуки для запросов или конвейеры агрегирования.
  • Всегда тщательно тестируйте хуки, чтобы убедиться в том, что они работают так, как ожидается, и не вызывают непредвиденных побочных эффектов.

Возьмите на заметку

Используя хуки, помните:

  • По умолчанию хуки асинхронны. Для обработки асинхронных операций используйте async/await или обратные вызовы на основе промисов, например next().
  • Контекст (this) хука зависит от его типа. Касательно хуков для документов  —  this относится к самому документу.
  • Можно связать в цепочку несколько pre- или post-хуков для одного и того же события, создавая мощный конвейер пользовательской логики.

Заключение

Хуки Mongoose  —  это универсальный инструмент, который может раскрыть весь потенциал приложений Mongoose. Экспериментируйте, изучайте и раскрывайте мощь этих ниндзя-шпионов для создания надежных и эффективных приложений, управляемых данными.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Siddiquiaffan: Mongoose Hooks: Everything You Need to Know

Предыдущая статьяБайт-код Java: назначение, структура и использование
Следующая статьяИскусство манипулирования массивами JavaScript: исследование метода Array.prototype.filter()