通过节点获取mongodb集合

时间:2014-10-30 23:36:14

标签: javascript node.js mongodb express mongoose

我很快表达/ mongo堆栈,所以问题很简单,无法在stackoverflow上找到任何可以解决我问题的东西,所以这里是:

我有一个看起来或多或少的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;

然后我要按照我的快递路线要求:

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;

我发送请求,我得到的结果是“未定义的”#39;所以没有任何东西从后端返回。

Db连接100%正确且有效。

我不完全确定,我是否必须在快速方面拥有架构定义,或者是否可以在不知道架构的情况下查询任何数据?

1 个答案:

答案 0 :(得分:1)

你在这里缺少的是一些" mongoose magic"这实际上正在发生"幕后"原样。它也是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;

因此,虽然您可能按顺序编码,但实际的事件顺序并不像您想象的那样。虽然您可以从基础驱动程序实现的db Db`对象中调用mongoose.connection ( and actually this is a connection object and not the对象,但不能保证数据库此时实际连接。事实上,它很可能不是。

此处的排序点是您的数据库连接实际发生 后从模块导出变量,而不是之前。它不会等待完成上一行,也不能让它完成。

Mongoose本身更倾向于"模型"表示数据库中的集合。因此,一般方法是定义这些模型对象并使用它们来访问数据:

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
    });
});

因此,模型对象实际上是为您做的,并提供了自己的标准方法实现,例如" find"," update"等

如果你不想做这种包装,模型的定义似乎太多了,甚至在这里使用{ strict: false }修饰符,这有效地放松了对模式的约束允许任何数据,那么你最好使用基本驱动程序而不是猫鼬。

但是当然你想要的东西比将回调中的所有代码都包装到连接中更聪明。这是一种定义对象的方法,您可以使用它来获取" fetch"您的数据库连接,并确保在建立连接之前不执行任何操作:

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();
    });
  }
);

这基本上包裹了一个我们叫做的对象#34; Model&#34;这里,使用.getDb()的单一方法。该方法只接受一个回调,这就是你想要访问数据库的实际代码片段,这反过来会从连接中公开Db对象。

Db对象存储在该对象的内部,因此它基本上只是一个连接到数据库一次的单例。但是当你的逻辑在一个回调函数中传递时,它将只传递现有的存储对象,或者在传递代码之前等待连接。

样本用法的输出应为:

  呼叫模型
      再次呼叫模型
      连接
      db定义为       这里也定义了db

这显示了事件的实际发生顺序。

因此有不同的方法来处理这个问题。猫鼬模型&#34;抽象&#34;对你来说很多。您当然可以采用示例中给出的基本驱动程序的基本方法,或者进一步采用并实现您自己的连接系统,包括重写方法,这些方法与mongoose在下面执行的操作大致相同。还有其他包装库已经做到了这一点,没有通常由mongoose固有的模式概念。

基本上,基本驱动程序上方的每个更高级别的库都与所描述的相同,其中包含方法的包装器以确保连接在那里而无需将所有代码嵌入到事件侦听器中检查那个。