Next.js и проблема лимита подключений к MongoDB
Next.js — это популярная среда рендеринга на стороне сервера (SSR), которая позволяет разработчикам создавать быстрые и масштабируемые веб-приложения. MongoDB, с другой стороны, представляет собой документно-ориентированную базу данных NoSQL, которая широко используется для хранения и извлечения данных в веб-приложениях. Хотя Next.js и MongoDB могут без проблем работать вместе, существует потенциальная проблема, о которой следует знать разработчикам: проблема с ограничением количества подключений MongoDB.
Что такое проблема ограничения подключения MongoDB?
MongoDB имеет ограничение на количество соединений, которые могут быть открыты в любой момент времени. Это ограничение устанавливается параметром maxPoolSize в драйвере MongoDB. По умолчанию для maxPoolSize установлено значение 100, что означает, что в любой момент времени может быть открыто не более 100 подключений. Если приложение попытается открыть больше подключений, чем максимальное ограничение, MongoDB начнет отклонять новые подключения, и приложение может перестать отвечать на запросы.
В приложении Next.js каждый входящий запрос создает новый экземпляр приложения. Это означает, что если несколько запросов выполняются одновременно, приложение может попытаться открыть больше подключений, чем максимальное ограничение, и может возникнуть проблема ограничения подключений MongoDB.
Как решить проблему ограничения подключения MongoDB в Next.js?
Чтобы решить проблему ограничения соединений MongoDB в приложении Next.js, мы можем использовать шаблон проектирования Singleton. Шаблон Singleton гарантирует, что существует только один экземпляр класса, к которому можно получить глобальный доступ. В контексте приложения Next.js мы можем использовать шаблон Singleton для создания одного соединения MongoDB, которое можно использовать во всех экземплярах приложения.
Неправильное использование
export default async function handler(req, res) {
const MONGODB_URI = `URI`;
const MONGODB_DB = 'DB';
let client = new MongoClient(MONGODB_URI, {
useUnifiedTopology: true,
useNewUrlParser: true
});
await client.connect();
let db = client.db(MONGODB_DB);
try {
if (req.method === 'GET') {
const collection = db.collection('COLLECTION');
let data;
if (req.query.id) {
data = await collection.findOne({
_id: new ObjectId(req.query.id.toString())
});
} else {
data = await collection.find({}).toArray();
}
res.status(200).json({
message: 'Success! ',
data: data
});
}
} catch (error) {
console.log(error);
}
}
Основная проблема здесь в том, что при каждом запросе открывается новое соединение, а старое остается открытым. Неизбежным исходом в данной ситуации является такой результат. Количество подключений увеличится, и MongoDB перестанет отвечать на запросы.

Плохое решение
export default async function handler(req, res) {
const MONGODB_URI = `URI`;
const MONGODB_DB = 'DB';
let client = new MongoClient(MONGODB_URI, {
useUnifiedTopology: true,
useNewUrlParser: true
});
await client.connect();
let db = client.db(MONGODB_DB);
try {
if (req.method === 'GET') {
const collection = db.collection('COLLECTION');
let data;
if (req.query.id) {
data = await collection.findOne({
_id: new ObjectId(req.query.id.toString())
});
} else {
data = await collection.find({}).toArray();
}
res.status(200).json({
message: 'Success! ',
data: data
});
}
} catch (error) {
console.log(error);
} finally {
await client.close();
}
}
Решить проблему можно, закрыв соединение вручную по окончании операции. Однако закрытие старого соединения и открытие нового каждый раз приведет к резкому снижению производительности.
Лучшее решение
Напомним, что у нас есть доступ к глобальному объекту Node.js. Сохраняя соединение MongoDB в глобальном объекте и проверяя, существует ли оно уже, мы можем предотвратить создание нового соединения и избежать любых потенциальных проблем, которые могут возникнуть из-за нескольких соединений.
export default async function handler(req, res) {
const MONGODB_URI = `URI`;
const MONGODB_DB = 'DB';
async function getDb() {
if (!global.mongoClient) {
global.mongoClient = new MongoClient(MONGODB_URI, {
useUnifiedTopology: true,
useNewUrlParser: true,
}).connect();
}
const client = await global.mongoClient;
return client.db(MONGODB_DB);
}
let db = await getDb();
try {
if (req.method === 'GET') {
const collection = db.collection('COLLECTION');
let data;
if (req.query.id) {
data = await collection.findOne({
_id: new ObjectId(req.query.id.toString())
});
} else {
data = await collection.find({}).toArray();
}
res.status(200).json({
message: 'Success! ',
data: data
});
}
} catch (error) {
console.log(error);
}
}
Использование шаблона Singleton для создания одного подключения к MongoDB в приложении Next.js может помочь предотвратить проблему с ограничением подключения к MongoDB и гарантировать, что приложение останется стабильным и отзывчивым.
Заключение
Я не совсем уверен, что использование API Next.js является оптимальным подходом для подключения к базе данных и выполнения операций CRUD. Однако бывают случаи, когда нам может понадобиться использовать этот подход. В таких случаях важно убедиться, что приложение стабильно и работает правильно.