2014-10-30 110 views
0

我很新的快遞/蒙戈棧,所以這個問題是非常簡單的,無法找到任何計算器這將解決我的問題,所以在這裏它是:獲取MongoDB的集合與節點

我有一個index.js文件看起來或多或少是這樣的:

var mongoose = require('mongoose'); 

// Connections 
var developmentDb = 'mongodb://localhost/admin'; 
var usedDb; 

// If we're in development... 
if (process.env.NODE_ENV === 'development') { 
    // set our database to the development one 
    usedDb = developmentDb; 
    // connect to it via mongoose 
    mongoose.connect(usedDb); 
} 

// 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; 

然後我requireing它在我的快遞路線是這樣的:

var express = require('express'); 
var router = express.Router(); 
var db = require('../../database'); 

/* GET users listing. */ 
router.get('/', function(req, res) { 
    var users = db.collection('users'); 
    var test = users.find(); 
    res.send(test); 
}); 

module.exports = router; 

我發送請求,結果我得到是'你ndefined',所以沒有任何東西從後端返回。

Db連接是100%正確的並且有效。

我不完全確定,我必須在表達方面有一個模式定義,還是有可能在不知道模式的情況下查詢任何數據?

+0

出於好奇,你在Meteor.js中使用mongo嗎? – 2014-10-30 23:41:57

+0

不,我創建了自己的MeanStack - Mongodb,Express,Angular,Node顯然 – matewilk 2014-10-30 23:48:38

回答

1

你在這裏失蹤的是一種「貓鼬魔法」,它實際上是在「幕後」發生的。這也是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在這裏被定義以及

和表示事件的順序以及它們實際發生的順序。

所以有不同的方法來處理這個問題。貓鼬模型爲你「抽象」了很多。您當然可以採用基礎驅動程序(如示例中給出的那樣),或者採取進一步措施並實施您自己的連接系統,包括重複執行的方法,這些方法可以完成與貓鼬下面所做的大部分操作相同的操作。還有其他的包裝庫已經做到了這一點,而沒有模式概念,這也是貓鼬通常固有的。

基本上,基礎驅動程序上方的每個更高級別的庫都與上述內容大致相同,其中包含方法的包裝以確保連接在那裏,而無需將所有代碼嵌入到事件偵聽器中正在檢查。

+0

非常感謝您的重播,這個答案非常出色,我非常感謝。我沒有時間檢查解決方案,因爲一些非常直接的項目彈出。我會盡快回復,並確定我會投票,當我的聲望達到15時:) – matewilk 2014-11-18 22:17:09