Основи баз даних
VTFK • 2025
Лекція 18: GROUP BY & Window Functions
Фокус: аналіз даних у NoSQL
Послідовність етапів, кожен з яких трансформує документи для отримання результату.
Аналогія: Як конвеєр на фабриці: дані проходять через фази
Послідовність обробки
| Операція | Назва | Приклад |
|---|---|---|
| $match | Фільтр | {$match: {age: {$gt: 25}}} |
| $group | Агрегація | {$group: {_id: '$country', count: {$sum: 1}}} |
| $sort | Сортування | {$sort: {count: -1}} |
| $limit | Обмеження | {$limit: 10} |
| $project | Вибір полів | {$project: {name: 1, age: 1}} |
| $lookup | JOIN | {$lookup: {from: 'orders', ...}} |
Користувачи по країнах
db.users.aggregate([
// Етап 1: Фільтр
{ $match: { active: true } },
// Етап 2: Групування
{
$group: {
_id: '$country',
count: { $sum: 1 },
avg_age: { $avg: '$age' }
}
},
// Етап 3: Сортування
{ $sort: { count: -1 } },
// Етап 4: Обмеження
{ $limit: 5 }
]);
Додаємо індекси
// Простий індекс
db.users.createIndex({ email: 1 });
// Descending
db.orders.createIndex({ created_at: -1 });
// Композитний індекс
db.orders.createIndex({ user_id: 1, created_at: -1 });
// Унікальний індекс
db.users.createIndex({ email: 1 }, { unique: true });
// Текстовий індекс
db.posts.createIndex({ title: 'text', content: 'text' });
Об'єднання колекцій
db.orders.aggregate([
{
$lookup: {
from: 'users',
localField: 'user_id',
foreignField: '_id',
as: 'user_info'
}
},
{ $unwind: '$user_info' }, // розгорнути масив
{
$project: {
order_id: '$_id',
user_name: '$user_info.name',
amount: 1
}
}
]);
$match спочатку зменшує документи, потім $group на менших наборах швидче.
Повільні запити без індексів
// Повільно: без індексу
db.users.find({ email: 'test@example.com' }); // full table scan
БД сканує кожний документ
// Швидко: з індексом
db.users.createIndex({ email: 1 });
db.users.find({ email: 'test@example.com' }); // index lookup
Індекс знаходить документ швидко
Від простого до складного
insert/find/update/delete
Первa версія pipeline
$lookup для JOIN
Vector search вбудований
З JOIN та агрегацією
db.orders.aggregate([
{ $match: { created_at: { $gte: new Date('2025-01-01') } } },
{ $lookup: { from: 'users', localField: 'user_id', foreignField: '_id', as: 'user' } },
{ $unwind: '$user' },
{ $group: { _id: '$user.name', total_spent: { $sum: '$amount' }, order_count: { $sum: 1 } } },
{ $sort: { total_spent: -1 } },
{ $limit: 10 },
{ $project: { _id: 1, total_spent: 1, order_count: 1 } }
]);
Далі — індекси у SQL
Лекція 20: Індекси
Дякую за увагу! 💾