Llamadas de función síncrona para el controlador mongodb nodejs

Tengo un proyecto de código abierto que se ocupa de la base de datos mongodb. Estoy tratando de hacer una función que consulta la base de datos para verificar si existe una entrada.

El problema es que si if_exists() devuelve verdadero o falso, devuelve undefined ya que la función del controlador mongodb es asíncrona. El archivo es Query.js y he intentado la solución aquí para solucionar el problema. ¿Cuál es la forma correcta de realizar una consulta MongoDB síncrona en Node.js? pero aún así obtengo un resultado indefinido con el método get.

¿Cuál es la mejor manera de hacer que esto funcione?

La salida de las pruebas unitarias es la siguiente:

 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 } ] 

Puedes navegar los códigos completos en WeaponXI / cplog

O para un vistazo rápido, el código de query.js es:

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

Solución:

Query.js Query.test.js Gists

Gracias JohnnyHK!

No puede utilizar un resultado asíncrono como el valor de retorno de una función. Es así de simple. Debe entregar el resultado asíncrono a la persona que llama a través de una callback que se proporciona como un parámetro para la función (o usar futuros / promesas y diferir efectivamente ese paso, pero eso es más complicado).

if_exists debería verse así en su lugar:

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