【问题标题】:Synchronous function calls for nodejs mongodb drivernodejs mongodb驱动的同步函数调用
【发布时间】:2012-12-03 01:14:07
【问题描述】:

我有一个处理 mongodb 数据库的开源项目。我正在尝试创建一个查询数据库以检查条目是否存在的函数。

问题是当 if_exists() 返回 true 或 false 时它返回 undefined,因为 mongodb 驱动程序函数是异步的。该文件是Query.js,我在这里尝试了解决问题What is the right way to make a synchronous MongoDB query in Node.js? 的解决方案,但使用get 方法仍然得到未定义的结果。

完成这项工作的最佳方法是什么?

单元测试的输出如下:

running unit tests...
add query test
exists tests:
get: undefined
{}
should be true: undefined
get: undefined
{}
should be false:undefined
Captains Logs listening on port 3000
Captains_Logs v0.5.0-21
[ { name: 'rhcp', _id: 50cbdcbe9c3cf97203000002 } ]
[ { name: 'os', _id: 50cbdcbe9c3cf97203000001 } ]

您可以在WeaponXI/cplog浏览整个代码

或者快速查看 query.js 代码是:

var DB = require('../../lib/db.js').DB;

function methods() {
  //query object
  var Q = {};
  //will act as our private variables to workaround asynchronous functions.
  //will delete non-required ones when done -- we don't have to, but just for continuity.
  exports.privates = {};




  //add tag to collection
  Q.add = function(tag) {
    if (typeof tag === "string") {
      //maybe we are adding a tag by name
      var obj = {
        name: tag
      };
    } else if (typeof tag === "object" && tag.name) {
      //maybe the tag object was specified, and tag's name was provided
      var obj = tag;
    }

    require('mongodb').connect(DB.mongo_url, function(err, db) {
      db.collection('tags', function(err, coll) {
        coll.insert(obj, {
          safe: true
        }, function(err, result) {
          console.log(result);

        });

      });
    });
  }
  var callback = {
    _set: function(key, val) {
      exports.privates[key] = val;
      //console.log(JSON.stringify(privates));
    },
    _get: function(key) {
      console.log("get: "+exports.privates.key);
      console.log(JSON.stringify(exports.privates));
      return exports.privates[key];
    },
    _unset: function(key) {
      delete privates[key];
    }
  }
  var if_exists = function(query, where, callback) {

    require('mongodb').connect(DB.mongo_url, function(err, db) {
      db.collection(where, function(err, coll) {
        coll.findOne(query, function(e, r) {
          //console.log(r);
          if (r === null) {
            callback._set("does_exist", false);
          } else {
            callback._set("does_exist", true);
          }

        });
      });
    });

    var result = callback._get("does_exist");
    // delete privates.does_exist;

    return result;
  }

  Q.if_exists = function(query, where) {
    if_exists(query, where, callback);

  }



  return Q;
}

var query = exports.query = methods();

function unit_test_add() {
  console.log("add query test");
  query.add("os");
  query.add({
    name: "rhcp"
  });
}

function unit_test_if_exists() {
  console.log("exists tests:");
  console.log("should be true: " + query.if_exists({
    name: "os"
  }, "tags"));
  console.log("should be false:" + query.if_exists({
    name: "ossuruk"
  }, "tags"));

}

function unit_tests() {
  console.log("running unit tests...");
  unit_test_add();
  unit_test_if_exists();

}
unit_tests();

解决办法:

Query.js Query.test.js Gists

感谢 JohnnyHK!

【问题讨论】:

  • 其他方式:执行query.if_exists( .. ,.. ,function(answer){console.log('..

标签: javascript node.js mongodb node-mongodb-native


【解决方案1】:

不能使用异步结果作为函数的返回值。就是这么简单。您必须通过作为函数参数提供的回调将异步结果传递给调用者(或使用期货/承诺并有效地推迟该步骤,但这涉及更多)。

if_exists 应该是这样的:

var if_exists = function(query, where, callback) {

  require('mongodb').connect(DB.mongo_url, function(err, db) {
    db.collection(where, function(err, coll) {
      coll.findOne(query, function(e, r) {
        //console.log(r);
        if (r === null) {
          callback(e, false);
        } else {
          callback(e, true);
        }
        // You should either close db here or connect during start up
        // and leave it open.
        db.close();
      });
    });
  });
}

【讨论】:

  • 啊,谢谢,我现在就试试。顺便说一句,有两个函数连接数据库,我认为当函数结束时它关闭了(我只是从示例中复制了代码,但它们没有关闭)。在我的情况下,脚本会打开两个连接并且从不关闭它们?我可以像这样开始连接:require('mongodb').connect(DB.mongo_url, function(err, db) { DB.conn = db; }); 并在 if_exists 函数中使用DB.conn.collection( ... ) 吗?如果我做这样的事情,我应该在哪里关闭?
  • @Logan 是的,类似的东西应该可以工作。它实际上是您通过 connect 调用打开的连接池,您可以在应用关闭期间关闭它(或者在应用关闭时让系统清理它)。
  • 谢谢!它按照你的建议工作。在我意识到应该如何完成回调之前,我不敢相信我试图以一种非常模糊的方式来做这件事。还要感谢您提供有关连接问题的说明。我也会试试的。这是适用于您的建议的解决方案。 gist.github.com/4291691.git
  • 我不明白,这不是限制应用程序吗?为什么不是这样可以根据查询结果设置变量,从而实现面向对象的数据库查询......我希望有一个很好的理由。
  • @Logan 不,你的 node.js 代码都在一个线程中运行;这里的关键概念是异步函数和回调。
猜你喜欢
  • 2013-07-07
  • 1970-01-01
  • 2017-06-08
  • 2017-03-25
  • 1970-01-01
  • 1970-01-01
  • 2018-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多