Pluginy w Mongoose to doskonały sposób na rozszerzenie funkcjonalności modeli i schematów. Umożliwiają dodanie powtarzalnych, niestandardowych funkcji do modeli, co przyspiesza pracę i zwiększa elastyczność aplikacji. W tym artykule omówimy, czym są pluginy, pokażemy przykłady popularnych pluginów oraz zaprezentujemy, jak stworzyć własny plugin.
Co to są pluginy?
Pluginy to moduły, które możemy dodać do schematu w Mongoose, aby wzbogacić go o dodatkowe funkcje. Każdy plugin to funkcja, która może modyfikować schemat, dodawać niestandardowe właściwości, metody, walidatory lub middleware do modelu.
Dzięki pluginom możemy łatwo dodać funkcje takie jak walidacja unikalności, śledzenie czasu tworzenia i aktualizacji dokumentów, a także tworzyć własne, niestandardowe funkcjonalności.
Przykładowe pluginy
1. Plugin mongoose-unique-validator
Plugin mongoose-unique-validator jest popularnym narzędziem, które ułatwia walidację unikalności pól w modelu. W MongoDB indeksy unikalne nie są automatycznie walidowane przez Mongoose, więc mongoose-unique-validator zapewnia dodatkową warstwę walidacji.
Instalacja
Aby zainstalować plugin mongoose-unique-validator, użyj poniższej komendy:
npm install mongoose-unique-validator
Użycie w schemacie
Po zainstalowaniu, możemy go dodać do modelu użytkownika, aby wymusić unikalność adresu e-mail.
const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const userSchema = new mongoose.Schema({
username: { type: String, required: true },
email: { type: String, required: true, unique: true }
});
// Dodanie pluginu do schematu
userSchema.plugin(uniqueValidator, { message: 'Error, expected {PATH} to be unique.' });
const User = mongoose.model('User', userSchema);
W tym przykładzie, jeśli spróbujemy dodać użytkownika z istniejącym adresem e-mail, plugin zgłosi błąd i zwróci komunikat o braku unikalności. Jest to przydatne do zachowania spójności danych.
2. Plugin timestamps
Plugin timestamps automatycznie dodaje pola createdAt i updatedAt do każdego dokumentu, które przechowują informacje o czasie utworzenia i ostatniej aktualizacji dokumentu. Jest to bardzo przydatne, gdy chcemy śledzić, kiedy dokument został utworzony i ostatnio zmodyfikowany.
Użycie timestamps
timestamps nie wymaga instalacji jako zewnętrzny moduł, ponieważ jest wbudowany w Mongoose. Aby dodać go do schematu, wystarczy przekazać opcję timestamps przy tworzeniu schematu:
const postSchema = new mongoose.Schema({
title: { type: String, required: true },
content: String
}, { timestamps: true });
const Post = mongoose.model('Post', postSchema);
Dzięki timestamps, każde utworzenie lub modyfikacja dokumentu automatycznie zaktualizuje wartości pól createdAt i updatedAt. Jest to świetne rozwiązanie dla aplikacji, które wymagają śledzenia czasu, np. do analizy aktywności użytkowników.
Tworzenie własnych pluginów
Oprócz gotowych rozwiązań, Mongoose pozwala na tworzenie własnych pluginów, które możemy wielokrotnie używać w różnych schematach. Tworząc plugin, możemy dodawać własne właściwości, metody i middleware.
Przykład: Plugin do maskowania hasła
Załóżmy, że chcemy stworzyć plugin, który maskuje (czyli np. hashuje) hasło użytkownika przed zapisaniem go w bazie. Do hashowania możemy użyć biblioteki bcrypt.
Instalacja bcrypt
npm install bcrypt
Tworzenie pluginu do hashowania hasła
Najpierw definiujemy plugin jako funkcję, która dodaje middleware do schematu, a następnie używamy go w modelu User.
const bcrypt = require('bcrypt');
function passwordHashingPlugin(schema, options) {
schema.pre('save', async function (next) {
if (this.isModified('password')) {
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
}
next();
});
}
Ten plugin dodaje pre middleware dla operacji save, które hashują hasło przed zapisaniem go w bazie. Jeśli hasło nie jest zmienione, middleware nie wykonuje żadnych operacji.
Użycie pluginu w schemacie
Następnie możemy dodać ten plugin do schematu użytkownika:
const mongoose = require('mongoose');
const passwordHashingPlugin = require('./passwordHashingPlugin'); // Ścieżka do stworzonego pluginu
const userSchema = new mongoose.Schema({
username: { type: String, required: true },
password: { type: String, required: true }
});
// Dodanie pluginu do schematu
userSchema.plugin(passwordHashingPlugin);
const User = mongoose.model('User', userSchema);
Dzięki temu każdy zapis użytkownika automatycznie zahashuje hasło przed zapisaniem go do bazy, co podnosi bezpieczeństwo przechowywania danych.
Przykład: Plugin do śledzenia logów operacji
Stwórzmy kolejny plugin, który będzie logować wszystkie operacje zapisu i aktualizacji w konsoli. Będzie to przydatne w procesie debugowania i śledzenia operacji.
function loggingPlugin(schema, options) {
schema.pre('save', function (next) {
console.log(`Zapisywanie dokumentu: ${JSON.stringify(this)}`);
next();
});
schema.pre('updateOne', function (next) {
console.log(`Aktualizacja dokumentu: ${JSON.stringify(this)}`);
next();
});
}
Ten plugin dodaje dwa pre middleware: jedno dla operacji save i jedno dla updateOne, które wyświetlają w konsoli szczegóły dokumentu przed zapisaniem lub aktualizacją.
Użycie pluginu do logowania w schemacie
Dodajmy go do schematu Post:
const postSchema = new mongoose.Schema({
title: { type: String, required: true },
content: String
});
// Dodanie pluginu logującego
postSchema.plugin(loggingPlugin);
const Post = mongoose.model('Post', postSchema);
Za każdym razem, gdy dokument Post jest zapisywany lub aktualizowany, plugin wyświetli informacje o operacji w konsoli, co pomoże śledzić zmiany w czasie rzeczywistym.
Podsumowanie
Pluginy w Mongoose oferują elastyczność i powtarzalność, która pozwala na łatwe rozszerzenie funkcji modeli. W tym artykule omówiliśmy:
- Gotowe pluginy takie jak
mongoose-unique-validatordo walidacji unikalności oraztimestampsdo automatycznego śledzenia czasu. - Tworzenie własnych pluginów – zobaczyliśmy, jak stworzyć plugin do hashowania hasła oraz plugin do logowania operacji.
Dzięki pluginom możemy ułatwić zarządzanie kodem, poprawić bezpieczeństwo danych i śledzić operacje w bazie, co podnosi jakość aplikacji. Własne pluginy są świetnym sposobem na budowanie modułowych i skalowalnych funkcji, które można wielokrotnie wykorzystywać w różnych projektach.