2014-01-05 2 views
5

У меня есть файл db.js, в котором я установил соединение MongoDB. Я хотел бы экспортировать объект базы данных в мой основной файл app.js:Как экспортировать объект, доступный только при обратном вызове async?

// db.js 
require('mongodb').MongoClient.connect(/* the URL */, function (err, db) { 
    module.exports = db; 
}); 

// app.js 
var db = require('./db'); 

app.get('/', function (req, res) { 
    db.collection(/* … */); // throws error 
}); 

Ошибка:

TypeError: Object # has no method 'collection'

Итак, как я могу экспортировать db объект правильно?

+1

Как насчет экспорта, как ' экспорт = требуется ('') MongoDB MongoClient.connect;. '. Затем выполните запрос и сделайте что-нибудь внутри обратного вызова? – elclanrs

+0

На первый взгляд кажется, что это должно сработать. Что вы видите, если вы выполните console.log (db) после var db = require ('./db') и внутри обратного вызова app.get? И вы попробовали console.log (db) внутри обратного вызова connect db.js? –

+0

@elclanrs Извините, я не следую. –

ответ

3

Самый лучший вариант, так как suggested in the comments по elclanrs, является экспорт обещание: (. Я использую удивительный Q библиотеку здесь)

// database.js 
var MongoClient = require('mongodb').MongoClient, 
    Q = require('q'), 
    connect = Q.nbind(MongoClient.connect, MongoClient); 

var promise = connect(/* url */);   

module.exports = { 
    connect: function() { 
    return promise; 
    } 
} 

// app.js 
var database = require('./database'); 

database.connect() 
    .then(function (db) { 
    app.get('/', function (req, res) { 
     db.collection(/* … */); 
    }); 
    }) 
    .catch(function (err) { 
    console.log('Error connecting to DB:', err); 
    }) 
    .done(); 


Ниже старая версия моего ответ, оставленный ради истории (но если вы не хотите использовать обещания, вместо того, чтобы идти по этой дороге, вы должны использовать Matt's answer).

Его недостатком является то, что он открывает соединение каждый раз, когда вы require('database.js)

// DO NOT USE: left for the sake of history 

// database.js 
var MongoClient = require('mongodb').MongoClient; 

function connect(cb) { 
    MongoClient.connect(/* the URL */, cb); 
} 

module.exports = { 
    connect: connect 
} 

// app.js 
var database = require('./database'); 

database.connect(function (err, db) { 
    app.get('/', function (req, res) { 
     db.collection(/* … */); 
    }); 
}); 
+0

В этом случае он должен открыть соединение в каждом файле, не так ли? – thefourtheye

+2

Я предполагаю, или, может быть, выставляю обещание, затем цепь? – elclanrs

+0

@elclanrs mmm ... Что-то в этом роде. Это интересный вопрос. – thefourtheye

0

Серверы обычно имеют 3 фазы (облом!): Первонач, служить и uninit. Это кажется очевидным, но когда вы начинаете писать серверы с нуля (т. Е. На Java вы начинаете наследовать от HttpServlet), иногда вы забываете, как это делать ...

На этапе запуска вы должны открыть соединение db (пул) и сохраните объект где-нибудь (как правило, в вашем модуле db.js). Затем на этапе обслуживания извлеките соединение mongodb от db.js.

Похожие: How to get a instance of db from node-mongo native driver?

2

Вы не можете сделать это, как вы хотите это сделать, потому что, цитирую the docs:

Note that assignment to module.exports must be done immediately. It cannot be done in any callbacks.

Вместо однако, вы можете присвоить свойство из module.exports в обратный вызов, поэтому это будет работать;

// db.js 
require('mongodb').MongoClient.connect(/* the URL */, function (err, db) { 
    module.exports.instance = db; 
}); 

// app.js 
var db = require('./db'); 

// some time later (when `.instance` is available) 
app.get('/', function (req, res) { 
    db.instance.collection(/* … */); 
}); 

Однако спустя некоторое время немного боли, так что вы можете просто хотите использовать какое-то функцию обратного вызова;

// db.js 
var queue = []; 
var instance = null; 

require('mongodb').MongoClient.connect(/* the URL */, function (err, db) { 
    instance = db; 

    while (queue.length) { 
     queue.pop()(instance); 
    } 
}); 

module.exports.done = function (callback) { 
    if (instance === null) { 
     queue.push(callback); 
    } else { 
     callback(instance); 
    } 
}; 

// app.js 
require('./db').done(function (db) { 
    app.get('/', function (req, res) { 
     db.collection(/* … */); 
    }); 
}); 

Вышесказанное также обрабатывает случаи, когда обработчики через done() прикреплены после уже устанавливается соединение.

+0

+1, вы можете показать, как обращаться с делом «err». – thefourtheye

0

В коде:

// db.js 
require('mongodb').MongoClient.connect(/* the URL */, function (err, db) { 
    module.exports = db; 
}); 

// app.js 
var db = require('./db'); 

app.get('/', function (req, res) { 
    db.collection(/* … */); // throws error 
}); 

Вы называли connect в db.js классе, но это асинхронно.

Вызов в app.js к require синхронно в поведении, хотя, так что он всегда получит неопределенное значение (как exports не будет присвоено значение в то время db.js закончил выполнение).

Я предлагаю держать вещи простыми.

Опция, которую я обычно использую, - это то, где код приложения делает соединение и не запускает прослушивание HTTP-соединений до тех пор, пока он не будет завершен. Затем я инициализирую каждый файл route, вызвав именованный метод и передав ему соединение с базой данных.

Или вы всегда можете вызвать соединение в каждом модуле, но кешируйте значение. (Вызов вызова должен быть вызван в коде обратного вызова маршрута, чтобы маршруты были определены сразу, а не когда соединение было фактически установлено).

// db.js 
var _db = null; 
exports = function(callback) { 
    if (!_db) { 
     _db = {}; // only one connection, so we'll stop others from trying 
     require('mongodb').MongoClient.connect(/* the URL */, function (err, db) { 
      _db = db; 
      callback(err, db); 
     }); 
    } else { 
     callback(null, _db); 
    } 
}; 

// app.js 

var db = require('./db'); 
db(function(err, connection) { 
    // store the connection value here and pass around, or ... 
    // call this always in each file ... 
}); 
/// or ... 

app.get('/', function (req, res) { 
    db(function(err, connection) { 
     connection.collection(/* … */); 
    }); 
}); 

Или, вы можете использовать MongooseJS (обертку для родного драйвера NodeJS MongoDB), где команда, и т.д. находится в очереди, если соединение не доступно ....

Смежные вопросы