Mongoose oferuje zaawansowane możliwości, które znacznie rozszerzają możliwości MongoDB. Dziś przyjrzymy się dwóm potężnym funkcjom: agregacji oraz indeksom. Agregacja pozwala na złożone przetwarzanie danych, a indeksy umożliwiają optymalizację zapytań i poprawę wydajności.
Agregacja: Używanie pipeline’u agregacyjnego
Agregacja to funkcja MongoDB umożliwiająca przetwarzanie i analizowanie danych poprzez stosowanie sekwencji operacji (pipeline’u). Agregacje są idealne, gdy potrzebujemy bardziej zaawansowanych analiz niż proste zapytania .find().
Podstawy pipeline’u agregacyjnego
Pipeline agregacyjny składa się z różnych etapów (stages), z których każdy wykonuje określoną operację na danych. Oto najpopularniejsze operacje:
$match: Filtruje dokumenty na podstawie kryteriów.$group: Grupuje dokumenty na podstawie określonych pól i umożliwia agregowanie wartości.$sort: Sortuje wyniki.$project: Wybiera lub modyfikuje pola w wynikach.
Przykład agregacji: Analiza zamówień
Załóżmy, że mamy kolekcję Order, która przechowuje zamówienia z polami customerId, amount i status. Chcemy znaleźć całkowitą kwotę zamówień dla każdego klienta, który ma zamówienia zrealizowane (status: "completed").
Schemat dla zamówień
const mongoose = require('mongoose');
const orderSchema = new mongoose.Schema({
customerId: mongoose.Schema.Types.ObjectId,
amount: Number,
status: String,
date: Date
});
const Order = mongoose.model('Order', orderSchema);
Pipeline agregacyjny
Poniższy przykład wykorzystuje pipeline agregacyjny do uzyskania sumy zamówień dla każdego klienta o statusie „completed”:
Order.aggregate([
{ $match: { status: 'completed' } }, // Filtruj zamówienia zrealizowane
{ $group: { _id: '$customerId', totalAmount: { $sum: '$amount' } } }, // Grupuj po customerId i sumuj amount
{ $sort: { totalAmount: -1 } } // Sortuj po sumie zamówień malejąco
])
.then(results => console.log('Suma zamówień dla klientów:', results))
.catch(error => console.log('Błąd agregacji:', error));
Wyjaśnienie pipeline’u:
- $match: Filtruje dokumenty, pozostawiając tylko zamówienia o statusie „completed”.
- $group: Grupuje dokumenty na podstawie
customerId, licząc sumę wartościamountdla każdego klienta. - $sort: Sortuje wyniki malejąco po
totalAmount.
Dzięki agregacji możemy analizować dane w bardzo zaawansowany sposób, co jest niezwykle przydatne przy raportach i statystykach.
Indeksy: Tworzenie i zarządzanie indeksami
Indeksy w MongoDB są strukturami danych, które poprawiają wydajność zapytań. Domyślnie MongoDB tworzy indeks _id dla każdego dokumentu, ale możemy tworzyć dodatkowe indeksy na innych polach, aby zoptymalizować wyszukiwanie.
Tworzenie indeksów w Mongoose
W Mongoose możemy dodać indeks bezpośrednio do schematu, używając opcji index. Załóżmy, że w schemacie Order chcemy utworzyć indeks na polach customerId i date dla szybszego wyszukiwania zamówień według klienta i daty.
Dodanie indeksu do schematu
const orderSchema = new mongoose.Schema({
customerId: mongoose.Schema.Types.ObjectId,
amount: Number,
status: String,
date: Date
});
// Dodaj indeks na customerId i date
orderSchema.index({ customerId: 1, date: -1 }); // 1 oznacza indeks rosnący, -1 malejący
const Order = mongoose.model('Order', orderSchema);
Powyższy kod tworzy indeks kompozytowy (na wielu polach), który pozwala na szybsze wyszukiwanie dokumentów według customerId i date.
Rodzaje indeksów
MongoDB oferuje różne typy indeksów, które można tworzyć za pomocą Mongoose:
- Indeks jednopolowy: Indeks na jednym polu, np.
{ email: 1 }. - Indeks kompozytowy: Indeks na wielu polach, np.
{ customerId: 1, date: -1 }. - Indeks unikalny: Umożliwia uniknięcie duplikatów, np.
{ email: 1, unique: true }. - Indeks tekstowy: Umożliwia pełnotekstowe wyszukiwanie, np.
{ content: 'text' }.
Przykład indeksu unikalnego
Załóżmy, że chcemy, aby pole email w kolekcji User było unikalne. Możemy dodać indeks unikalny:
const userSchema = new mongoose.Schema({
name: String,
email: { type: String, unique: true }, // Indeks unikalny na polu email
age: Number
});
const User = mongoose.model('User', userSchema);
Dzięki indeksowi unikalnemu MongoDB automatycznie zapobiegnie dodaniu dwóch dokumentów z takim samym adresem e-mail.
Zarządzanie indeksami
MongoDB automatycznie buduje indeksy, gdy są definiowane w schemacie, ale Mongoose oferuje także dodatkowe metody do zarządzania nimi.
Sprawdzanie indeksów
Aby sprawdzić, jakie indeksy są utworzone dla danej kolekcji, możemy użyć:
User.collection.getIndexes()
.then(indexes => console.log('Indeksy kolekcji User:', indexes))
.catch(error => console.log('Błąd sprawdzania indeksów:', error));
Usuwanie indeksów
Aby usunąć wszystkie indeksy w kolekcji, możemy skorzystać z:
User.collection.dropIndexes()
.then(() => console.log('Wszystkie indeksy zostały usunięte'))
.catch(error => console.log('Błąd usuwania indeksów:', error));
Możemy również usunąć konkretny indeks:
User.collection.dropIndex('email_1')
.then(() => console.log('Indeks email został usunięty'))
.catch(error => console.log('Błąd usuwania indeksu:', error));
Kiedy używać indeksów?
Indeksy są bardzo przydatne, gdy:
- Często wyszukujemy dane po konkretnym polu (np.
emaillubcustomerId). - Wyszukujemy dane na podstawie wielu pól (np.
customerIdidate). - Chcemy zapobiec duplikatom, używając indeksów unikalnych.
Należy jednak pamiętać, że nadmiar indeksów może zwiększyć wymagania pamięciowe i wydłużyć czas zapisu dokumentów. Warto tworzyć indeksy tylko na tych polach, które rzeczywiście przyspieszą zapytania.
Podsumowanie
Dzięki zaawansowanym operacjom Mongoose, takim jak agregacja i indeksowanie, możemy znacznie zwiększyć wydajność i elastyczność aplikacji:
- Agregacja pozwala na złożone przetwarzanie danych, idealne do raportów i analiz.
- Indeksy umożliwiają optymalizację zapytań, co znacząco przyspiesza dostęp do często wyszukiwanych danych.
Stosowanie tych funkcji pozwala na lepsze zarządzanie danymi i poprawia wydajność aplikacji w MongoDB. Agregacje są świetne do zaawansowanej analizy, natomiast indeksy są niezbędne dla aplikacji o wysokiej dostępności i dużym obciążeniu zapytań.