简体   繁体   English

使用节点获取mongodb集合

[英]Get mongodb collection with node

I'm very new to express/mongo stack, so the question is pretty simple, couldn't find anything on stackoverflow which would resolve my problem, so here it is: 我对表达/ mongo堆栈很陌生,所以问题很简单,在stackoverflow上找不到任何可以解决我问题的东西,所以这里是:

I have a index.js file which looks more or less like this: 我有一个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;

Then I'm requireing it in my express route like this: 然后,我在这样的快速路线中要求它:

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;

I'm sending request and the result I'm getting is 'undefined' so nothing is returned from the back end. 我正在发送请求,得到的结果是“未定义”,因此后端未返回任何内容。

Db connection is 100% correct and works. DB连接是100%正确并且可以正常工作。

I'm not entirely sure, do I have to have a schema definition on express side, or is it possible to query any data, without knowing the schema? 我不能完全确定,我是否必须在快速方面有一个架构定义,还是可以在不了解该架构的情况下查询任何数据?

What you are missing here is a bit of the "mongoose magic" that is actually happening "behind the scenes " as it were. 您在这里所缺少的是一些“猫鼬魔术”,实际上是在“幕后”发生的。 It's also a base concept of most operations in node.js that the operations ( particularly where IO is concerned ) are largely asynchronous in nature, so you are generally working with callbacks that fire when the operation is complete. 这也是node.js中大多数操作的基本概念,即这些操作(尤其是在涉及IO的情况下)实际上本质上是异步的,因此您通常使用的是在操作完成时触发的回调。

Take this part of your listing: 采取您的清单的此部分:

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

So while you may have coded that in sequence, the actual order of events is not as you might think. 因此,尽管您可能已经按顺序进行了编码,但是事件的实际顺序并不像您想象的那样。 While you can call the db object from mongoose.connection ( and actually this is a connection object and not the Db` object as implemented by the underlying driver ) there is no guarantee that the database is actually connected at this time. 尽管您可以从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`对象),但不能保证此时数据库实际上已连接。 In fact, in all likelihood it is not. 实际上,事实并非如此。

The sort point here is that your database connection actually happens after you export the variable from the module, and not before. 这里的排序点是,数据库连接实际上是从模块中导出变量之后而不是之前进行的。 It does not wait for the preceding line to complete, nor can you make it do so. 它不等待上一行完成,也不能这样做。

Mongoose itself rather has a concept of "models" to represent the collections in your database. 猫鼬本身更具有“模型”的概念来表示数据库中的集合。 So the general approach is to define these model objects and use them for accessing the data: 因此,通常的方法是定义这些模型对象并将其用于访问数据:

var Model = mongoose.model( 'Model', modelSchema, 'optionalCollectionName' );

Model.find({}, function(err,data) { 
   // do stuff in the callback
});

Part of the reason for this ( aside from the schema definitions that are attached ) is that there is actually something else going on here related to the connection. 造成这种情况的部分原因(除了附带的模式定义以外)实际上是在进行与连接有关的其他操作。 These objects in fact have internal logic that only processes the actions on the tied "collection" object only when the connection to the database is available. 这些对象实际上具有内部逻辑,仅在与数据库的连接可用时才处理绑定的“集合”对象上的操作。 So there is an "internal callback" function that is happening here where an internal connection object is actually being used. 因此,这里发生了一个“内部回调”函数,其中实际使用了内部连接对象。

Here is some simple code that "overrides" the usage of the internal methods to just try and get the underlying collection object from the driver. 这是一些简单的代码,它们“重写”内部方法的使用,以仅尝试从驱动程序中获取基础集合对象。 It will fail: 它将失败:

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

Since this asked for the collection object as implemented in the underlying driver to be returned and the native .find() method from that object to be used, the problem occurs that the database is not actually connected yet. 由于这要求返回在底层驱动程序中实现的集合对象,并要求使用该对象的本机.find()方法,因此出现了尚未实际连接数据库的问题。 So in order to make this work, you would need to wrap the call inside an event handler that fired only when the database was truly connected. 因此,为了使此工作正常进行,您需要将调用包装在事件处理程序中,该事件处理程序仅在真正连接数据库时才触发。 Or otherwise make sure that a connection had been made before this was called: 否则,请确保在调用之前已建立连接:

mongoose.connection.on('open',function(err,conn) {

    // Now we know we are connected.
    Model.collection.find({}, function(err,data) { 
       // do stuff in the callback
    });
});

So the model objects are actually doing this for you, and are providing their own implementations of the standard methods such as "find", "update" etc. 因此,模型对象实际上是在为您执行此操作,并提供了它们自己的标准方法(例如“查找”,“更新”等)的实现。

If you don't want to do this kind of wrapping, and the definition of models seems like too much work, and even using the { strict: false } modifier here, which relaxes the constraints on the schema to effectively allow any data, then you are probably better off using the base driver rather than mongoose. 如果您不想进行这种包装,并且模型的定义似乎工作量很大,甚至使用此处的{ strict: false }修饰符,它可以放宽对模式的约束以有效地允许任何数据,然后您最好使用基本驱动程序而不是猫鼬。

But of course you want something smarter than just wrapping all the code inside a callback to the connection. 但是,当然,您需要比将所有代码包装在连接的回调中更聪明的方法。 Here is one approach to define an object that you can use to "fetch" the database connection for you, and make sure that nothing is executed until that connection is made: 这是一种定义对象的方法,可用于为您“获取”数据库连接,并确保在建立该连接之前不执行任何操作:

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

That basically wraps up an object which we called "Model" here, with a single method to .getDb() . 这基本上是通过.getDb()的单个方法包装了一个在这里称为“模型”的对象。 That method simply accepts a callback, which is there to be your actual piece of code that you want to access the database with, which in turn exposes the Db object from the connection. 该方法只接受一个回调,即存在您要用来访问数据库的实际代码段,该代码进而从连接中公开Db对象。

The Db object is stored internally in that object, so it is basically a singleton which only ever connects to the database once. Db对象内部存储在该对象中,因此它基本上是单例,仅一次连接到数据库。 But as your logic is passed in aa callback function, then it will either just pass in the existing stored object, or wait until the connection is made before passing in the code. 但是,由于您的逻辑是通过回调函数传递的,因此它要么只是传递现有的存储对象,要么等到建立连接后再传递代码。

Output from the sample usage should be: 样本用法的输出应为:

call model 通话模型
call model again 再次调用模型
Connected 连接的
db is defined db已定义
db is defined here as well db也在这里定义

And that shows the order of events to how they actually happen. 这表明了事件的顺序以及它们如何实际发生。

So there are different ways to handle this. 因此,有不同的处理方式。 Mongoose models "abstract" a lot of that for you. 猫鼬模型为您“抽象”了很多。 You can of course either take a base approach with the base driver as given in the example, or take that further and implement your own connection system including overridden methods that does much of the same thing that mongoose is doing underneath. 当然,您可以按照示例中的说明使用基本驱动程序进行基本处理,也可以更进一步实现自己的连接系统,包括覆盖的方法,这些方法执行的功能与猫鼬在下面做的很多事情相同。 There are also other wrapper libraries that already do this without the schema concepts that is generally inherent to mongoose as well. 还有其他包装器库已经执行了此操作,而没有猫鼬通常固有的架构概念。

Basically though, every higher level library above the base driver is doing much the same as described, where there are wrappers around the methods to make sure the connection is there without needing to embed all of your code in an event listener that is checking for that. 不过,基本上,基本驱动程序之上的每个更高级别的库都与上述操作大致相同,其中方法周围都有包装程序,以确保存在连接,而无需将所有代码都嵌入到检查该事件的侦听器中。

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

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