繁体   English   中英

使用节点获取mongodb集合

[英]Get mongodb collection with node

我对表达/ 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;

我正在发送请求,得到的结果是“未定义”,因此后端未返回任何内容。

DB连接是100%正确并且可以正常工作。

我不能完全确定,我是否必须在快速方面有一个架构定义,还是可以在不了解该架构的情况下查询任何数据?

您在这里所缺少的是一些“猫鼬魔术”,实际上是在“幕后”发生的。 这也是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调用db对象mongoose.connection ( and actually this is a connection object and not the底层驱动程序实现mongoose.connection ( and actually this is a connection object and not the 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已定义
db也在这里定义

这表明了事件的顺序以及它们如何实际发生。

因此,有不同的处理方式。 猫鼬模型为您“抽象”了很多。 当然,您可以按照示例中的说明使用基本驱动程序进行基本处理,也可以更进一步实现自己的连接系统,包括覆盖的方法,这些方法执行的功能与猫鼬在下面做的很多事情相同。 还有其他包装器库已经执行了此操作,而没有猫鼬通常固有的架构概念。

不过,基本上,基本驱动程序之上的每个更高级别的库都与上述操作大致相同,其中方法周围都有包装程序,以确保存在连接,而无需将所有代码都嵌入到检查该事件的侦听器中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM