5 мощных оптимизаций для увеличения запросов Mongoose
Привет всем, это Джосс. Сегодня я покажу вам 5 мощных оптимизаций для увеличения запросов Mongoose.
Что такое Мангуст?
Mongoose — это популярная библиотека моделирования объектных данных (ODM) для Node.js и MongoDB. Он упрощает взаимодействие с базой данных, позволяя разработчикам легко определять схемы, создавать модели и выполнять различные операции CRUD. Однако по мере роста приложений эффективная обработка большого количества запросов Mongoose становится критически важной для поддержания оптимальной производительности. В этой статье мы рассмотрим пять мощных оптимизаций, которые могут значительно повысить эффективность запросов Mongoose, обеспечивая более плавное взаимодействие с вашей базой данных MongoDB.
Индексация для скорости
Индексы играют решающую роль в повышении производительности запросов. Без индексов MongoDB должна выполнять сканирование коллекции, что может быть довольно медленным для больших наборов данных. Создавая соответствующие индексы, вы можете сократить время, затрачиваемое на поиск документов, и значительно ускорить операции чтения. Анализируйте часто используемые поля в запросах и при необходимости создавайте составные индексы.
⚠️ Имейте в виду, что создание индексов для каждого поля может привести к увеличению объема памяти и времени записи, поэтому сосредоточьтесь на полях, которые часто запрашиваются.
const userSchema = new mongoose.Schema({ username: { type: String, unique: true }, email: { type: String, index: true }, age: { type: Number } });
Ограничение и пропуск запросов с разбивкой на страницы
При работе с большими наборами данных обычно реализуется разбиение на страницы для извлечения данных меньшими управляемыми фрагментами. Mongoose предоставляет методы limit()
и skip()
, которые можно использовать для получения данных на страницах. Однако очень важно использовать их с осторожностью, так как skip()
может привести к снижению производительности при работе с большими наборами данных. Рассмотрите возможность использования разбивки на страницы с помощью курсора, например поля createdAt
, чтобы обеспечить стабильную производительность независимо от количества страниц.
const pageNumber = 2; const pageSize = 10; const users = await User .find() .skip((pageNumber - 1) * pageSize) .limit(pageSize);
Как упоминалось ранее, разбиение на страницы с помощью курсора является более эффективным подходом к обработке больших наборов данных. Вместо того, чтобы полагаться исключительно на skip()
, который может стать медленным по мере увеличения количества пропущенных документов, используйте курсор для разбиения на страницы набора данных. Курсор представляет собой указатель на определенную позицию в наборе данных, что позволяет эффективно выбирать следующую страницу данных.
Пример разбиения на страницы с помощью курсора с использованием поля createdAt
:
async function getNextPage(lastDocumentCreationDate, pageSize) { const query = lastDocumentCreationDate ? { createdAt: { $lt: lastDocumentCreationDate } } : {}; const users = await User.find(query) .sort({ createdAt: -1 }) // Sort by createdAt in descending order (newest first) .limit(pageSize); return users; } const pageSize = 10; // will return 10 newest users const firstPage = await getNextPage(null, pageSize); // To get the next page of users const lastUserCreationDate = firstPage[firstPage.length - 1].createdAt; const secondPage = await getNextPage(lastUserCreationDate, pageSize);
Бережливые запросы для снижения накладных расходов
По умолчанию запросы Mongoose возвращают документы Mongoose, что сопряжено с некоторыми накладными расходами из-за предлагаемых ими дополнительных функций. Однако, если вам нужны только необработанные объекты JavaScript, вы можете использовать метод lean()
, чтобы сократить время обработки и объем памяти. При использовании lean()
результатом запроса является не экземпляр документа Mongoose, а простой объект JavaScript.
const users = await User.find().lean();
⚠️ Недостатком включения lean
является то, что в бережливых документах нет:
- Отслеживание изменений
- Кастинг и проверка
- Геттеры и сеттеры
- Виртуалы
save()
Выберите только необходимые поля
Минимизируйте данные, извлекаемые из базы данных, выбирая только необходимые поля в своих запросах. Эта оптимизация особенно важна при работе с большими документами с вложенными структурами. Ограничив данные, отправляемые по сети, можно значительно улучшить время ответа на запрос.
const users = await User.find().select('username email');
Используйте операции массовой записи
При работе с несколькими операциями записи рассмотрите возможность использования операций массовой записи, таких как insertMany()
, updateMany()
и deleteMany()
, вместо отдельных запросов. Операции массовой записи могут быть более эффективными, поскольку они сокращают количество обращений к базе данных.
Пример создания множества пользователей:
const newUsers = [ { username: 'user1', email: '[email protected]' }, { username: 'user2', email: '[email protected]' } ]; await User.insertMany(newUsers);
Другим подходящим примером может быть этот:
Предполагая, что у вас есть модель User
, определенная, как и раньше, с добавлением поля score
:
const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({ username: { type: String, required: true }, email: { type: String, required: true }, age: { type: Number, required: true }, createdAt: { type: Date, default: Date.now }, score: { type: Number, default: 0 } // New 'score' field added }); const User = mongoose.model('User', userSchema);
Вы можете использовать метод bulkWrite для обновления оценки некоторых пользователей за один раз:
// Function to update the score for multiple users async function updateScores(scoreUpdates) { const bulkOperations = scoreUpdates.map((update) => { const { userId, points } = update; const updateOperation = points >= 0 ? '$inc' : '$dec'; // Use '$inc' for adding points and '$dec' for removing points return { updateOne: { filter: { _id: userId }, [updateOperation]: { score: Math.abs(points) // Ensure points are a positive value } } }; }); try { const result = await User.bulkWrite(bulkOperations); // call Mongo only 1 time instead of 3 console.log(`${result.modifiedCount} users' scores updated successfully.`); } catch (error) { console.error('Error updating scores:', error); } } // Example usage: const scoreUpdates = [ { userId: 'user1Id', points: 5 }, // Add 5 points to user1 { userId: 'user2Id', points: -3 }, // Remove 3 points from user2 { userId: 'user3Id', points: 10 } // Add 10 points to user3 ]; updateScores(scoreUpdates);
Заключение
Внедрив эти пять мощных оптимизаций, вы можете значительно повысить производительность своих запросов Mongoose. Надлежащее индексирование, разбиение на страницы, бережливые запросы, выборочное извлечение полей и массовые операции записи — ценные инструменты, обеспечивающие беспрепятственное взаимодействие вашего приложения Node.js с базой данных MongoDB даже по мере роста вашего набора данных. Не забывайте отслеживать и тестировать производительность после применения этих оптимизаций, чтобы точно настроить приложение и обеспечить бесперебойную работу пользователей. Удачного кодирования!