Синхронные вызовы функций для драйвера nodejs mongodb

У меня есть проект с открытым исходным кодом, который работает с базой данных mongodb. Я пытаюсь создать функцию, которая запрашивает базу данных, чтобы проверить, существует ли запись.

Проблема в том, что когда if_exists() возвращает true или false, он возвращает undefined, поскольку функция драйвера mongodb является асинхронной. Файл Query.js, и я пробовал решение здесь для обхода проблемы js">Как правильно выполнить синхронный запрос MongoDB в 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

Спасибо ДжонниХК!


person Logan    schedule 15.12.2012    source источник
comment
Наоборот: сделайте query.if_exists( .. ,.. ,function(answer){console.log('.. и т. д.   -  person Wrikken    schedule 15.12.2012


Ответы (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();
      });
    });
  });
}
person JohnnyHK    schedule 15.12.2012
comment
А, спасибо, сейчас попробую. Кстати, есть две функции, которые соединяют базу данных, и я думал, что она закрылась, когда функция была в конце (я как бы просто скопировал код из примеров, и они не закрылись). В моем случае скрипт открывает два соединения и никогда их не закрывает? Могу ли я сначала подключиться так: require('mongodb').connect(DB.mongo_url, function(err, db) { DB.conn = db; }); и использовать DB.conn.collection( ... ) в функции if_exists? Если я сделаю что-то подобное, где мне закрыть? - person Logan; 15.12.2012
comment
@Logan Да, что-то вроде этого должно работать. На самом деле это пул соединений, который вы открываете с помощью вызова connect, и вы закрываете его во время закрытия приложения (или просто позволяете системе очистить его, когда ваше приложение уходит). - person JohnnyHK; 15.12.2012
comment
спасибо! это сработало, как вы предложили. Я не могу поверить, что пытался сделать это действительно неясным способом, пока не понял, как должны были выполняться обратные вызовы. Также спасибо за примечания по проблемам с подключением. Я тоже попробую. Вот решение, которое сработало с вашими предложениями. gist.github.com/4291691.git - person Logan; 15.12.2012
comment
Я не понимаю, разве это не ограничивает применение? Почему нельзя установить переменную в соответствии с результатом запроса, таким образом, объектно-ориентируя запросы к базе данных... Я надеюсь, что для этого есть веская причина. - person Logan; 15.12.2012
comment
Что делает эти функции асинхронными? Это называется многопоточностью? Его нельзя взломать? - person Logan; 15.12.2012
comment
@Logan Это большие вопросы, на которые нелегко ответить в комментариях. Продолжайте читать о node.js, пока он не станет яснее, и публикуйте новые вопросы по мере необходимости. Начните здесь, если вы еще этого не читали. - person JohnnyHK; 15.12.2012
comment
Я понимаю, я буду читать больше на эту тему. Если бы вы могли дать мне несколько ключевых слов, хотя я был бы признателен. Должен ли я искать многопоточность (это то, как это называется?) Мне нужно небольшое руководство с точки зрения того, что исследовать, и терминологии. - person Logan; 16.12.2012
comment
@Logan Нет, весь ваш код node.js выполняется в одном потоке; ключевая концепция здесь асинхронные функции и обратные вызовы. - person JohnnyHK; 16.12.2012