你在這裏失蹤的是一種「貓鼬魔法」,它實際上是在「幕後」發生的。這也是node.js中大多數操作的基本概念,操作(特別是涉及IO的操作)在本質上大部分是異步的,所以您通常使用在操作完成時觸發的回調。
把你上市的這部分:
// get an instance of our connection to our database
var db = mongoose.connection;
db.once('open', function callback() {
console.log('Databsae Connection Successfully Opened at ' + usedDb);
});
module.exports = db;
因此,儘管你可能已經編碼的順序,事件的實際順序並不像你想象的。雖然您可以調用底層驅動程序實現的mongoose.connection (and actually this is a connection object and not the
Db對象中的db
對象),但不保證數據庫此時實際連接。事實上,它很可能不是。
這裏的分類點是你的數據庫連接實際上是你從模塊中導出變量,而不是之前。它不需要等待爲了完成上一行,也不能這樣做。
貓鼬本身相當有一個「模型」的概念來表示數據庫中的集合。所以,一般的方法是定義這些模型對象,並用它們來訪問數據:對於這種情況的原因(除了從所連接的架構定義)
var Model = mongoose.model('Model', modelSchema, 'optionalCollectionName');
Model.find({}, function(err,data) {
// do stuff in the callback
});
部分原因是,實際上是有什麼別的事情這裏與連接有關。這些對象實際上具有內部邏輯,僅當與數據庫的連接可用時才處理綁定「集合」對象上的操作。所以在這裏發生了一個「內部回調」函數,其中實際使用了一個內部連接對象。
下面是一些簡單的代碼,它「覆蓋」內部方法的用法,試圖從驅動程序獲取底層集合對象。它會失敗:
var mongoose = require('mongoose'),
Schema = mongoose.Schema
mongoose.connect('mongodb://localhost/test');
var modelSchema = new Schema({},{ strict: false });
var Model = mongoose.model('Model', modelSchema, 'optionalCollectionName');
Model.collection.find({}, function(err,data) {
// do stuff in the callback
});
由於這要求在底層驅動程序中實現要返回並使用來自該對象的本地.find()
方法的集合對象,出現的問題是數據庫沒有實際連接尚。所以爲了使這個工作,你需要將這個調用包裝在事件處理程序中,該處理程序只有在數據庫真正連接時纔會觸發。或以其他方式確保連接已經取得了在此之前被稱爲:
mongoose.connection.on('open',function(err,conn) {
// Now we know we are connected.
Model.collection.find({}, function(err,data) {
// do stuff in the callback
});
});
因此模型對象實際上這樣做對你來說,並提供自己的標準方法,如「發現」的實施,「更新「等
如果你不想做這種包裝,並且模型的定義看起來像太多的工作,甚至在這裏使用{ strict: false }
修飾符,這放鬆了對架構的約束以有效地允許任何數據,那麼你最好使用基礎驅動程序而不是貓鼬。
但是,當然,你想要的東西比將所有代碼包裝在回調中的所有代碼更智能。這裏有一個方法來定義一個對象,你可以用它來「取」爲你的數據庫連接,並確保直到建立連接沒有被執行:
var async = require('async'),
mongodb = require('mongodb'),
MongoClient = mongodb.MongoClient;
var Model = (function() {
var _db,
conlock;
return {
getDb: function(callback) {
var err = null;
if (_db == null && conlock == null) {
conlock = 1;
MongoClient.connect('mongodb://localhost/test',function(err,db) {
_db = db;
conlock == null;
if (!err) {
console.log("Connected")
}
callback(err,_db);
});
} else if (conlock != null) {
var count = 0;
async.whilst(
function() { return (_db == null) && (count < 5) },
function(callback) {
count++
setTimeout(callback,500);
},
function(err) {
if (count == 5)
err = new Error("connect wait exceeded");
callback(err,_db);
}
);
} else {
callback(err,_db);
}
}
};
})();
async.parallel(
[
function(callback) {
console.log("call model");
Model.getDb(function(err,db) {
if (err) throw err;
if (db != undefined)
console.log("db is defined");
callback();
});
},
function(callback) {
console.log("call model again");
Model.getDb(function(err,db) {
if (err) throw err;
if (db != undefined)
console.log("db is defined here as well");
callback();
});
}
],
function(err) {
Model.getDb(function(err,db) {
db.close();
});
}
);
,基本上包裝了一個對象,我們這裏稱爲「型號」,使用單一方法至.getDb()
。該方法只接受一個回調函數,這是您想要訪問數據庫的實際代碼片段,而該代碼片段將繼承該連接的Db
對象。
Db
對象被內部存儲在那個對象中,所以它基本上是一個單一的數據庫,它只連接到數據庫一次。但是因爲你的邏輯是通過一個回調函數傳遞的,所以它會傳入現有的存儲對象,或者在傳入代碼之前等待連接。
從樣品使用輸出應該是:
呼叫模型
呼叫模型再次
連接
分貝定義
DB在這裏被定義以及
和表示事件的順序以及它們實際發生的順序。
所以有不同的方法來處理這個問題。貓鼬模型爲你「抽象」了很多。您當然可以採用基礎驅動程序(如示例中給出的那樣),或者採取進一步措施並實施您自己的連接系統,包括重複執行的方法,這些方法可以完成與貓鼬下面所做的大部分操作相同的操作。還有其他的包裝庫已經做到了這一點,而沒有模式概念,這也是貓鼬通常固有的。
基本上,基礎驅動程序上方的每個更高級別的庫都與上述內容大致相同,其中包含方法的包裝以確保連接在那裏,而無需將所有代碼嵌入到事件偵聽器中正在檢查。
出於好奇,你在Meteor.js中使用mongo嗎? – 2014-10-30 23:41:57
不,我創建了自己的MeanStack - Mongodb,Express,Angular,Node顯然 – matewilk 2014-10-30 23:48:38