Подключение к Mongodb-Native-Driver в express.js

Я использую mongodb-native-driver в приложении express.js. У меня есть около 6 коллекций в базе данных, поэтому я создал 6 файлов js, каждый из которых имеет коллекцию как объект javascript (например, function collection(){}), а функции прототипов обрабатывают все манипуляции с этими коллекциями. Я думал, что это будет хорошая архитектура.

Но у меня возникла проблема: как подключиться к базе данных? Должен ли я создавать соединение в каждом из этих файлов и использовать их? Я думаю, что это было бы излишним, поскольку соединение в mongodb-native-driver создает пул соединений, и наличие нескольких из них было бы неоправданным.

Итак, как мне создать единый пул соединений и использовать его во всех файлах collections.js? Я хочу, чтобы соединение было реализовано в mongoose. Дайте мне знать, если какой-либо из моих мыслительных процессов в архитектуре приложения неверен.

Использование Mongoose могло бы решить эти проблемы, но я читал в нескольких местах, что он медленнее, чем собственный драйвер, а также я бы предпочел модели без схемы.

Изменить: я создал модуль из моделей. Каждая коллекция находилась в файле, и в качестве аргумента она принимала базу данных. Теперь в файле index.js я вызвал соединение с базой данных и сохранил переменную db после того, как получил базу данных из соединения. (Я использовал функцию автоматического повторного подключения, чтобы убедиться, что соединение не потеряно). В том же файле index.js я экспортировал каждую из коллекций следующим образом.

exports.model1 = require('./model1').(db)
exprorts.model2 = require('./model2').(db)

Это гарантировало, что часть базы данных обрабатывалась только в одном модуле, и приложение просто вызывало функцию, которую экспортировал каждый файл model.js, например save(), fincdbyid() и т. д. (whatever you do in the function is upto you to implement).


person Saransh Mohapatra    schedule 04.08.2013    source источник


Ответы (3)


как подключиться к базе данных?

Чтобы подключиться с помощью собственного драйвера MongoDB, вам нужно сделать что-то вроде следующего:

var util = require('util');
var mongodb = require('mongodb');
var client = mongodb.MongoClient;

var auth = {
    user: 'username',
    pass: 'password',
    host: 'hostname',
    port: 1337,
    name: 'databaseName'
};

var uri = util.format('mongodb://%s:%s@%s:%d/%s',
    auth.user, auth.pass, auth.host, auth.port, auth.name);

/** Connect to the Mongo database at the URI using the client */
client.connect(uri, { auto_reconnect: true }, function (err, database) {
    if (err) throw err;
    else if (!database) console.log('Unknown error connecting to database');
    else {

        console.log('Connected to MongoDB database server at:');
        console.log('\n\t%s\n', uri);

        // Create or access collections, etc here using the database object
    }
});

Базовое соединение настраивается следующим образом. Это все, что я могу вам дать, это просто базовое описание того, что вы хотите. Опубликуйте некоторый код, который у вас есть, чтобы получить более конкретную помощь.

Должен ли я создавать соединение в каждом из этих файлов и использовать их?

No.

Как мне создать единый пул соединений и использовать его во всех файлах collections.js?

Вы можете создать один файл с кодом, подобным приведенному выше, назовем его dbmanager.js для подключения к базе данных. Экспортируйте такие функции, как createUser, deleteUser и т. д., которые работают с вашей базой данных, а затем экспортируйте функциональность следующим образом:

module.exports = {
    createUser: function () { ; },
    deleteUser: function () { ; }
};

который вы могли бы затем require из другого файла вот так:

var dbman = require('./dbmanager');

dbman.createUser(userData); // using connection established in `dbmanager.js`

EDIT: Поскольку мы имеем дело с JavaScript и одним потоком, собственный драйвер действительно автоматически обрабатывает пул соединений для вас. Вы можете найти это по ссылкам StackOverflow ниже для получения дополнительных подтверждений этого. ОП также указывает это в вопросе. Это означает, что client.connect должен вызываться только один раз экземпляром вашего сервера. После того, как объект database будет успешно получен из вызова client.connect, этот объект database следует повторно использовать во всем экземпляре вашего приложения. Это легко сделать с помощью шаблона модуля, предоставляемого Node.JS.

Мое предложение состоит в том, чтобы создать модуль или набор модулей, которые служат единой точкой контакта для взаимодействия с базой данных. В моих приложениях у меня обычно есть один модуль, который зависит от родного драйвера и вызывает require('mongodb'). Все остальные модули в моем приложении не будут напрямую обращаться к базе данных, но вместо этого все манипуляции должны координироваться этим модулем базы данных.

Это инкапсулирует весь код, связанный с собственным драйвером, в один модуль или набор модулей. ОП, кажется, думает, что есть проблема с простым примером кода, который я опубликовал, описывая проблему с «одним большим закрытием» в моем примере. Это все довольно простые вещи, поэтому я добавляю разъяснения относительно базовой архитектуры, но я все еще не чувствую необходимости менять какой-либо код.

ОП также, кажется, думает, что здесь можно установить несколько соединений. Это невозможно с этой установкой. Если вы создали модуль, как я предлагаю выше, то при первом вызове require('./dbmanager') он выполнит код в файле dbmanager.js и вернет объект module.exports. Объект экспорта кэшируется и также возвращается при каждом последующем вызове require('./dbmanager'), однако код в dbmanager.js будет выполняться только в первый require.

Если вы не хотите создавать такой модуль, другим вариантом будет экспортировать только database, переданный в обратный вызов для client.connect, и использовать его напрямую в разных местах вашего приложения. Однако я рекомендую против этого, независимо от опасений ОП.

Подобные, возможно, повторяющиеся вопросы Stackoverflow, среди прочего:

person Cory Gross    schedule 04.08.2013
comment
Я рассмотрел решение, которое вы дали, но не стал его продвигать, потому что, как я сказал выше, у меня есть около 6 коллекций и идея написать все манипуляции внутри одного большого замыкания. Во-вторых, в вашем методе есть вероятность, что может быть установлено более одного соединения, поскольку он не проверяет, уже подключено или нет. - person Saransh Mohapatra; 05.08.2013
comment
Независимо от того, сколько раз вы require(./dbmanager)' it will not call client.connect` несколько раз. Единственный «шанс» того, что будет установлено более одного соединения, - это если вы запустите несколько экземпляров сервера. Node.JS выполнит код только в первый раз, когда это потребуется, возвращая только exports при каждом последующем вызове. - person Cory Gross; 05.08.2013
comment
-1 не хватает объяснения. Вопреки вашему комментарию, вы никогда ничего не упоминаете об одном закрытии в своем вопросе. Я конкретно отвечаю на каждый из ваших вопросов: они касались того, следует ли создавать соединения в нескольких разных файлах. Я остаюсь при своем ответе: в этом нет необходимости. - person Cory Gross; 05.08.2013
comment
Да, я не упомянул об этом в вопросе, но это не очень хорошая практика, и я чувствую, что прямо писать о следовании хорошей практике не важно. Отредактируйте свой ответ, чтобы избежать проблемы, и я также могу принять ответ. - person Saransh Mohapatra; 06.08.2013
comment
Я не уверен, что вы имеете в виду, редактируя мой вопрос, чтобы избежать проблемы. Вы не совсем понимаете, в чем именно, по вашему мнению, проблема. Это все довольно стандартные вещи. Пожалуйста, опубликуйте пример, если у вас есть способ улучшить мой код, даже в минимальной степени. Я хотел бы учиться. Вам не нужно писать все манипуляции внутри на одном большом закрытии. Ваши файлы в Node.JS — это модули, содержащиеся в замыкании, охватывающем весь файл. Каждая созданная в ней функция также будет иметь собственное замыкание. - person Cory Gross; 07.08.2013
comment
Спасибо за декларативный ответ..... Я очень ценю это. И это именно то решение, которое я сделал сам. Извините за -1, который я поставил раньше, но теперь я вернул его на +1. Надеюсь, вы сделаете то же самое и с вопросом. - person Saransh Mohapatra; 13.08.2013
comment
StackOverflow блокирует голоса спустя столько времени, что я не могу изменить свою оценку по моему вопросу, пока вопрос не будет отредактирован. Добавьте редактирование в свой вопрос, чтобы попытаться объяснить, как вы решили свою проблему, и я отменю свой предыдущий голос, я уверен, что это может помочь и другим. - person Cory Gross; 13.08.2013
comment
@CoryGross Сделано соответственно - person Saransh Mohapatra; 17.08.2013
comment
Ваш код правильный, но соединение устанавливается асинхронно. Лучший способ сделать это: blog.howarddierking .com/2014/07/01/ - person Ashish Rawat; 30.05.2016

Как говорится в принятом ответе, вы должны создать только одно соединение для всех входящих запросов и повторно использовать его, но в ответе отсутствует решение, которое создаст и кэширует соединение. Для этого я написал экспресс-промежуточное ПО — express-mongo-db. На первый взгляд эта задача тривиальна, и большинство людей используют такой код:

var db;
function createConnection(req, res, next) {
    if (db) { req.db = db; next(); }
    client.connect(uri, { auto_reconnect: true }, function (err, database) {
        req.db = db = databse;
        next();
    });
}

app.use(createConnection);

Но этот код приводит к утечке соединения, когда одновременно приходит несколько запросов, а db не определено. express-mongo-db решить эту проблему путем удержания входящих клиентов и вызова connect только один раз, когда требуется модуль (а не при поступлении первого запроса).

Надеюсь, что вы найдете ее полезной.

person floatdrop    schedule 08.08.2014

Я просто подумал, что добавлю свой собственный метод подключения к MongoDB для других, заинтересованных или имеющих проблемы с другими методами.

Этот метод предполагает, что вам не нужна аутентификация (я использую это на локальном хосте)

Аутентификацию по-прежнему легко реализовать

var MongoClient = require('mongodb').MongoClient;
var Server      = require('mongodb').Server;

var client = new MongoClient(new Server('localhost',27017,{
                                socketOptions: {connectTimeoutMS: 500},
                                poolSize:5,
                                auto_reconnect:true
                            }, {
                                numberOfRetries:3,
                                retryMilliseconds: 500
                            }));

client.open(function(err, client) {
    if(err) {
        console.log("Connection Failed Via Client Object.");
    } else {
        var db = client.db("theDbName");
        if(db) {
            console.log("Connected Via Client Object . . .");
            db.logout(function(err,result) {
                if(!err) {
                    console.log("Logged out successfully");
                }
                client.close();
                console.log("Connection closed");
            });
        }
    }
});

Кредит принадлежит Брэду Дэвли, который описывает этот метод в своей книге (стр. 231-232)

person Max    schedule 21.08.2014