#javascript #node.js #database #mongodb #mongodb-atlas
#javascript #node.js #База данных #mongodb #mongodb-atlas
Вопрос:
(узел: 21140) Предупреждение о необработанном отказе: Ошибка MongoError: топология закрыта, пожалуйста, подключитесь
Я думаю, что это ошибка, связанная с повторением client.connect и client.close в каждой функции операции CRUD, как показано в коде ниже
// Я думаю, что нет проблем с uri кластера, поэтому я не публиковал это, поскольку он нормально подключается
const MongoClient = require("mongodb").MongoClient;
const uri = "mongodb srv://username:pasword@some cluster";
//I think there is no issue with cluster uri so I didn't post that since it connects fine
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
async function AddnewService(service) {
await client.connect()
const database = client.db("twitch")
const usr = await database.collection("recipes").find({ Title: service.Title }).toArray()
if (usr.length >= 1) {
await client.close()
return { message: "Title already in use" }
}
else {
const result = await database.collection("recipes").insertOne(service)
await client.close()
return { message: "Service Added to Database" }
}
}
async function FetchAllserviceSearch(service) {
await client.connect()
const database = client.db("twitch")
let recipesCursor = await database.collection("recipes").find({})
while (await recipesCursor.hasNext()) { //make sure to put await on cursor .hasnext()
let recipe = await recipesCursor.next()
console.log(recipe)
}
await client.close()
return { message: "User Added to Database" }
}
module.exports = {
AddnewService,
FetchAllserviceSearch
}
Я попытался выделить, чтобы эти client.connect и client.close вызывались только один раз, но из-за этого всегда возникала новая ошибка.
Я не могу устранить module.export, потому что они мне нужны для использования в другом файле.
Поэтому мне нужна небольшая помощь, чтобы разобраться, как это сделать, без этого ненужного повторения, поскольку mongodbAtlas вызывает проблемы с этим.
Комментарии:
1. Что происходит, когда вы перемещаете следующую строку
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
внутри функции вместо сохранения на уровне глобального файла? можете ли вы проверить это и сообщить мне?2. @Sohan Привет, idk, если так и должно было быть, но я думаю, что это не приводит к повторению ошибки включения и выключения соединения. Я пробовал несколько раз, и я еще не получил эту ошибку .. есть ли в этом недостаток или это правильный способ сделать это?
3. Проверьте ответ ниже, возможно, вам потребуется выполнить некоторые изменения из приведенного ниже ответа в соответствии с вашими потребностями. Также, если вы используете express, вы можете сделать это при инициализации приложения global express
4. Также я бы посоветовал перейти на модульное программирование вместо того, чтобы хранить такие функции в одном классе.
5. @Sohan Я изучу это. Я все еще новичок в Mongo Atlas и других вещах, связанных с облачной платформой, поэтому не знал многих подходов к выполнению задач.
Ответ №1:
Не закрывайте соединение с БД, вы находитесь в состоянии гонки, когда поступают два запроса, один закрывается, другой открывается.
client.close(); -----> remove
Используйте одно и то же подключение к базе данных для всех запросов.
const uri = "mongodb srv://username:pasword@cluster0.ik1pu.mongodb.net/myFirstDatabase?retryWrites=trueamp;w=majority";
let con;
async function connect(service) {
if (con) return con; // return connection if already conncted
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
con = client.connect()
return con;
}
async function AddnewService(service) {
const client = await connect();
const database = client.db("twitch")
const usr = await database.collection("recipes").find({ Title: service.Title }).toArray()
if (usr.length >= 1) {
// await client.close(); -----> remove
return { message: "Title already in use" }
}
else {
const result = await database.collection("recipes").insertOne(service)
return { message: "Service Added to Database" }
}
}
async function FetchAllserviceSearch(service) {
const client = await connect();
const database = client.db("twitch")
let recipesCursor = await database.collection("recipes").find({})
while (await recipesCursor.hasNext()) { //make sure to put await on cursor .hasnext()
let recipe = await recipesCursor.next()
console.log(recipe)
}
// await client.close(); -----> remove
return { message: "User Added to Database" }
}
module.exports = {
AddnewService,
FetchAllserviceSearch
}
Комментарии:
1. @MuhammadUmarKhan какие ошибки вы получаете?
2. Нет, это была моя ошибка.. Я перепроверял это снова и снова, и это работает потрясающе.. Я имею в виду, что даже скорость запроса увеличилась. Idk, что произошло, но то, как вы научили меня подключаться, увеличило скорость CRUD в Mongo ATlas, и я больше не получаю эти ошибки. Теперь я применю это в основной части проекта, над которым я работаю. Надеюсь, ничего не пойдет не так. Спасибо
Я постараюсь понять, как вы заставили это соединение работать быстрее и без ошибок.
3. Мы вообще никогда не закрываем клиентское соединение?
4. @MuhammadUmarKhan Когда ваше приложение использует базу данных для запроса данных, вы можете избежать закрытия соединения. Вы можете написать логику для закрытия соединения перед выходом из приложения узла.
5. Понял. это проясняет ситуацию.
Ответ №2:
Вы пытаетесь закрыть клиент в обработчике запроса, но ваш клиент является глобальным.
Если вы хотите иметь глобальный клиент, не закрывайте его в обработчиках запросов.
Если вы хотите закрыть клиент в обработчиках запросов, создайте клиент в обработчике того же запроса.
Создайте класс подключения для управления подключением к базе данных приложений. MongoClient не предоставляет одноэлементный пул соединений, поэтому вы не хотите повторно вызывать MongoClient.connect()
его в своем приложении. Одноэлементный класс для переноса клиента mongo работает для большинства приложений, которые я видел.
const MongoClient = require('mongodb').MongoClient
class Connection {
static async open() {
if (this.db) return this.db
this.db = await MongoClient.connect(this.url, this.options)
return this.db
}
}
Connection.db = null
Connection.url = 'mongodb://127.0.0.1:27017/test_db'
Connection.options = {
bufferMaxEntries: 0,
reconnectTries: 5000,
useNewUrlParser: true,
useUnifiedTopology: true,
}
module.exports = { Connection }
Везде, где вы require('./Connection'
находитесь), Connection.connectToMongo()
метод будет доступен, как и свойство Connection.db, если оно было инициализировано.
const { Connection } = require('../lib/Connection.js')
async function AddnewService(service) {
// This should go in the app/server setup, and waited for.
await Connection.connectToMongo()
const database = Connection.db("twitch")
const usr = await database.collection("recipes").find({ Title: service.Title }).toArray()
if (usr.length >= 1) {
// await client.close()
return { message: "Title already in use" }
}
else {
const result = await database.collection("recipes").insertOne(service)
// await client.close()
return { message: "Service Added to Database" }
}
}
В express вы можете сделать что-то вроде этого,
import {MongoClient} from 'mongodb';
import express from 'express';
import bodyParser from 'body-parser';
let mongoClient = null;
MongoClient.connect(config.mongoURL, {useNewUrlParser: true, useUnifiedTopology: true},function (err, client) {
if(err) {
console.log('Mongo connection error');
} else {
console.log('Connected to mongo DB');
mongoClient = client;
}
})
let app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use((req,res,next)=>{
req.db = mongoClient.db('customer_support');
next();
});
И используйте в своих дескрипторах запросов, подобных этому,
router.post('/hello',async (req,res,next)=>{
let uname = req.body.username;
let userDetails = await AddnewService(req.db,uname) // change signature of this method
res.statusCode = 200;
res.data = userDetails;
next();
});
Комментарии:
1. Понял .. это прояснило ситуацию еще больше. спасибо allot за помощь. И я использую express.js
2. Итак, вы хотите настроить на глобальном уровне в express?
3. Я. то, что я обычно делаю в автономном MongoDB (не MongoAtlas), я создаю соединение один раз глобально, а затем позже просто использую вызовы функций позже. Я пытался имитировать этот метод в MongoAtlas, но все пошло наперекосяк.
4. Я обновил ответ на использование mongo client на глобальном уровне в express
5. Спасибо, я пока не проверю это и не попытаюсь понять