Основна налаштування та з'єднання
const mongoose = require('mongoose');
// З'єднання з обробкою помилок
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('Підключено до MongoDB');
}).catch(err => {
console.error('Помилка підключення до MongoDB:', err);
});
Кращі практики проєктування схеми
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true,
index: true // Додаємо індекс для полів, які часто запитуються
},
email: {
type: String,
required: true,
unique: true
},
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}],
metadata: {
lastLogin: Date,
loginCount: Number
}
}, {
timestamps: true // Автоматично додає createdAt та updatedAt
});
Ефективні запити
Основні запити
// Пошук з умовами
const users = await User.find({
age: { $gte: 18 },
'metadata.loginCount': { $gt: 5 }
}).select('username email'); // Вибір конкретних полів
// Складні запити з кількома умовами
const powerUsers = await User.find({
$and: [
{ 'metadata.loginCount': { $gt: 10 } },
{ posts: { $exists: true, $not: { $size: 0 } } }
]
});
Конвеєр агрегацій
const results = await User.aggregate([
// Етап фільтрації - відбір документів
{ $match: { age: { $gte: 18 } } },
// Етап групування - групування та підрахунок
{ $group: {
_id: '$country',
averageAge: { $avg: '$age' },
totalUsers: { $sum: 1 }
}},
// Етап сортування
{ $sort: { totalUsers: -1 } }
]);
Реалізація пагінації
Пагінація з використанням курсора
async function getCursorPaginatedResults(cursor, limit = 10) {
const query = cursor
? { _id: { $gt: cursor } }
: {};
const items = await Collection.find(query)
.sort({ _id: 1 })
.limit(limit + 1); // Отримуємо один додатковий елемент для перевірки на наявність більше результатів
const hasMore = items.length > limit;
const results = hasMore ? items.slice(0, -1) : items;
return {
items: results,
nextCursor: hasMore ? results[results.length - 1]._id : null
};
}
Пагінація з використанням відступу
async function getPagedResults(page = 1, limit = 10) {
const skip = (page - 1) * limit;
const [items, totalCount] = await Promise.all([
Collection.find({})
.skip(skip)
.limit(limit)
.sort({ createdAt: -1 }),
Collection.countDocuments({})
]);
return {
items,
currentPage: page,
totalPages: Math.ceil(totalCount / limit),
totalItems: totalCount
};
}
Оптимізація запитів
Створення індексів
// Індекс для одного поля
userSchema.index({ email: 1 });
// Композитний індекс
userSchema.index({ username: 1, createdAt: -1 });
// Текстовий індекс для пошуку
userSchema.index({
username: 'text',
bio: 'text'
});
Використання Explain для аналізу запитів
const explanation = await User.find({
username: /john/i
}).explain('executionStats');
console.log(explanation.executionStats);
Управління даними та їх обслуговування
Резервне копіювання та відновлення
# Резервне копіювання
mongodump --db=myapp --out=/backup/path
# Відновлення
mongorestore --db=myapp /backup/path/myapp
Валідація даних
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true,
validate: {
validator: function(v) {
return v.length >= 3;
},
message: 'Назва продукту має містити не менше 3 символів'
}
},
price: {
type: Number,
min: [0, 'Ціна не може бути від’ємною']
}
});
Поради щодо продуктивності
1.
Використання проєкцій
// Погано - отримує всі поля
await User.findOne({ _id: userId });
// Добре - отримує лише необхідні поля
await User.findOne({ _id: userId })
.select('username email');
Пакетні операції
// Використовуйте пакетні операції для кількох оновлень
const bulk = User.collection.initializeUnorderedBulkOp();
users.forEach(user => {
bulk.find({ _id: user._id })
.updateOne({ $set: { status: 'active' } });
});
await bulk.execute();
Кешування часто запитуваних даних
const cache = new Map();
async function getUserWithCache(userId) {
if (cache.has(userId)) {
return cache.get(userId);
}
const user = await User.findById(userId);
cache.set(userId, user);
return user;
}
Список перевірки для моніторингу та обслуговування
Регулярний моніторинг
- Моніторити продуктивність запитів
- Перевіряти використання індексів
- Моніторити вільний простір на диску
-
Відстежувати використання пулу з’єднань
Обслуговування бази даних
-
Регулярне створення резервних копій
-
Оптимізація індексів
-
Стратегії архівації даних
-
Ротація журналів
Заходи безпеки
- Контроль доступу на основі ролей
- Мережна безпека
- Регулярні перевірки безпеки
- Шифрування за допомогою SSL/TLS
Пам’ятайте: управління базою даних — це безперервний процес. Регулярно переглядайте та оптимізуйте конструкцію вашої бази даних, запити та процедури обслуговування відповідно до змінних потреб вашого застосунку.
Перекладено з: MongoDB Database Management & Query Optimization Guide