Mongoose to popularna biblioteka do pracy z MongoDB, jednak praca z dużą ilością danych lub aplikacjami produkcyjnymi wymaga zastosowania najlepszych praktyk i optymalizacji. W tym artykule omówimy, jak zadbać o zarządzanie błędami, optymalizację zapytań oraz bezpieczeństwo danych, aby nasza aplikacja była wydajna, bezpieczna i stabilna.
Zarządzanie błędami
Zarządzanie błędami jest kluczowym aspektem każdej aplikacji. Poniżej znajdziesz praktyki, które pozwolą na skuteczną obsługę błędów w Mongoose i zapewnienie stabilności aplikacji.
Obsługa błędów w operacjach Mongoose
Mongoose korzysta z obiektów Promise, więc każdą operację można owinąć w blok try...catch (przy asynchronicznych funkcjach) lub użyć metod .then() i .catch().
Przykład obsługi błędów w operacji zapisu:
const newUser = new User({
name: 'Anna Nowak',
email: 'anna@example.com',
age: 30
});
newUser.save()
.then(user => console.log('Użytkownik zapisany:', user))
.catch(error => {
if (error.name === 'ValidationError') {
console.log('Błąd walidacji:', error.message);
} else if (error.code === 11000) {
console.log('Błąd unikalności:', 'Email już istnieje');
} else {
console.log('Inny błąd:', error.message);
}
});
W tym przykładzie:
- Błędy walidacji są wyłapywane i obsługiwane oddzielnie.
- Błędy unikalności (np. email już istnieje) są rozpoznawane po kodzie błędu
11000. - Wszystkie inne błędy są również logowane, co pozwala lepiej zrozumieć potencjalne problemy.
Praktyki zapewniające stabilność aplikacji
- Używaj walidacji w schematach – Mongoose pozwala definiować wymagania dla pól (np.
required,min,max). Używanie walidacji w schematach zapobiega przechowywaniu niepoprawnych danych. - Centralne zarządzanie błędami – Tworzenie funkcji obsługi błędów i globalnego middleware do przechwytywania błędów w aplikacjach Express ułatwia obsługę i rejestrowanie błędów.
- Unikaj ładowania nadmiaru danych – Większe zapytania mogą przeciążać bazę danych. Staraj się pobierać tylko potrzebne dane (o czym więcej w części o optymalizacji zapytań).
Optymalizacja zapytań
Optymalizacja zapytań może znacząco poprawić wydajność aplikacji. W Mongoose znajdziesz wiele opcji, które pomogą ograniczyć ilość danych zwracanych przez MongoDB i przyspieszyć działanie aplikacji.
Zrozumienie, jak działa mechanizm lean()
Metoda lean() pozwala przyspieszyć zapytania, zwracając zwykłe obiekty JavaScript zamiast instancji Mongoose. Obiekty te nie mają metod Mongoose, takich jak .save() czy .populate(), co czyni je lżejszymi i szybszymi w przetwarzaniu.
Przykład użycia lean():
User.find({ age: { $gt: 18 } }).lean()
.then(users => console.log('Użytkownicy:', users))
.catch(error => console.log('Błąd wyszukiwania:', error));
Dzięki lean() to zapytanie działa szybciej i zużywa mniej pamięci. To świetne rozwiązanie, gdy dane nie muszą być modyfikowane, a jedynie odczytane.
Efektywne korzystanie z indeksów i paginacji
Indeksy pozwalają na szybsze wyszukiwanie danych i są niezbędne w aplikacjach, które przetwarzają duże zbiory danych. Mongoose pozwala na definiowanie indeksów bezpośrednio w schemacie.
Tworzenie indeksu na polu email w modelu User:
const userSchema = new mongoose.Schema({
name: String,
email: { type: String, unique: true, index: true }, // Indeks na polu email
age: Number
});
Paginacja
Paginacja jest niezbędna, gdy mamy do czynienia z dużą ilością wyników, np. w aplikacjach z przeglądaniem list użytkowników, zamówień itp.
const page = 2;
const limit = 10;
User.find()
.skip((page - 1) * limit)
.limit(limit)
.then(users => console.log('Strona użytkowników:', users))
.catch(error => console.log('Błąd wyszukiwania:', error));
W powyższym kodzie:
skippomija odpowiednią liczbę dokumentów, zależnie od strony.limitogranicza liczbę dokumentów, które mają być zwrócone.
Dzięki tej metodzie uzyskujemy wydajne przetwarzanie danych przy jednoczesnym zmniejszeniu obciążenia bazy danych.
Bezpieczeństwo danych
Bezpieczeństwo danych to absolutna podstawa w każdej aplikacji produkcyjnej. Mongoose dostarcza narzędzia, które pozwalają poprawić bezpieczeństwo i zapobiegać potencjalnym podatnościom.
Unikanie podatności: Walidacja danych wejściowych
Jednym z kluczowych aspektów bezpieczeństwa jest walidacja danych wejściowych. Używanie walidacji w schematach Mongoose jest pierwszym krokiem do ochrony danych.
Przykład walidacji w schemacie:
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
minlength: 3,
maxlength: 20
},
email: {
type: String,
required: true,
unique: true,
match: /.+\@.+\..+/ // Walidacja formatu email
},
password: {
type: String,
required: true,
minlength: 8
}
});
Dzięki tej walidacji:
- username musi mieć długość od 3 do 20 znaków.
- email musi być unikalny i pasować do formatu e-mail.
- password musi mieć co najmniej 8 znaków.
Najlepsze praktyki w zakresie przechowywania i operowania na danych
Hashuj hasła – Przechowywanie haseł jako tekstu jawnego to ogromne zagrożenie bezpieczeństwa. Użyj np.
bcrypt, aby zahashować hasła przed zapisaniem ich w bazie.
const bcrypt = require('bcrypt');
userSchema.pre('save', async function (next) {
if (this.isModified('password')) {
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
}
next();
});
Dzięki temu każde hasło jest przechowywane w postaci zaszyfrowanej.
- Zabezpiecz dostęp do danych – Upewnij się, że wrażliwe dane, takie jak hasła lub tokeny, nie są zwracane przez API.
userSchema.methods.toJSON = function () {
const userObject = this.toObject();
delete userObject.password; // Usunięcie hasła z odpowiedzi
return userObject;
};
W ten sposób metoda toJSON usuwa hasło z odpowiedzi, zanim dane trafią do użytkownika.
- Ogranicz poziomy dostępu – Używaj różnych poziomów dostępu (np.
admin,user) i weryfikuj, kto może wykonać daną akcję. Mongoose ułatwia dodawanie logiki, która sprawdza rolę użytkownika przed wykonaniem określonej operacji.
Podsumowanie
Zastosowanie najlepszych praktyk w pracy z Mongoose pozwala na tworzenie aplikacji, które są:- Stabilne dzięki odpowiedniemu zarządzaniu błędami,
- Wydajne dzięki optymalizacji zapytań i użyciu indeksów oraz paginacji,
- Bezpieczne poprzez walidację, szyfrowanie i kontrolę dostępu.