在express.js路由器函数中从mongo返回数据

时间:2016-03-18 21:58:18

标签: javascript node.js mongodb express

我正在尝试编写一个简单的验证函数,它接受一个mongo_id并检查它是否存在。我能够走到这一步,但我无法将该结果传递回调用该函数的路径。

这个函数基于一个浮动的例子......它确实有效。

validateUserId = function(userId) {

  var MongoClient = require('mongodb').MongoClient;
  var assert = require('assert');

  var options = {
    mongos: {
      ssl: false,
      sslValidate: false,
    }
  }
  isValid = false;
  MongoClient.connect(vars["MONGO_URL"], options, function(err, db) {
    assert.equal(null, err);
    var q = db.collection("users").find({
      _id: userId
    }, {
      _id: 1
    }).toArray(function(err, record) {
      assert.equal(null, err);
      record.forEach(function(r) {
        console.log(r);
        if (r._id == userId) {
          isValid = true;
        }
      });
      db.close();
      return isValid;
    })
  });
  return isValid;

};

此功能不会返回任何内容。

如何根据查询结果正确修改此代码以返回true / false值?

我们的想法是不必将此代码放入需要进行验证的每个路径中,只需在执行其他任务(不需要访问或连接到mongodb)之前调用validateUserId()。

例如:

app.get("/performVerifiedAction",function(req,res){
	if(validateUserId(req.query['userId'])){
		res.send("You may pass");
	}else{
		res.send("Can't figure out who you are");
	}
	return true;
});

2 个答案:

答案 0 :(得分:0)

validUserId实际上是一个异步函数。

按照Node.js中的惯例,异步函数在其最后一个参数中收到回调,请参阅How to write asynchronous functions for Node.js

Node.js style callbacks之后,callback参数是一个在第二个参数中接收异步操作结果的函数。

// callback is a function that gets isValid as its second arguments
// by convention the first argument of these callback function is any error 
// that may occur in this async operation.
validateUserId = function(userId, callback) {

  var MongoClient = require('mongodb').MongoClient;
  var assert = require('assert');

  var options = {
    mongos: {
      ssl: false,
      sslValidate: false,
    }
  }
  isValid = false;
  MongoClient.connect(vars["MONGO_URL"], options, function(err, db) {
    assert.equal(null, err);
    var q = db.collection("users").find({
      _id: userId
    }, {
      _id: 1
    }).toArray(function(err, record) {
      assert.equal(null, err);
      record.forEach(function(r) {
        console.log(r);
        if (r._id == userId) {
          isValid = true;
        }
      });
      db.close();
      return callback(null, isValid); // instead of return isValid;
    })
  });
  return callback(null, isValid); // instead of return isValid;

};

这是您使用validUserId异步功能的方法:

app.get("/performVerifiedAction",function(req,res){
  validateUserId(req.query['userId'], function(error, isValid) {
    if(isValid) {
      res.send("You may pass");
    } else {
      res.send("Can't figure out who you are");  
    }
  });
});

请注意,您可以通过处理错误(将err传递给callback并从函数返回)来大量改进上述代码。例如:

  MongoClient.connect(vars["MONGO_URL"], options, function(err, db) {
    assert.equal(null, err);
    // ...

可以改进为:

  MongoClient.connect(vars["MONGO_URL"], options, function(err, db) {
    if(!!err) { 
      return callback(err); 
    }
    //...

答案 1 :(得分:0)

Node.js调用外部服务的方法是异步的。这意味着调用MongoDb函数不会阻止程序执行,因此您的validateUserId函数将始终返回false,因为稍后将调用MongoDb查找回调并且不会修改已返回的值。

要在许多路由上使用此验证,您可以将此方法修改为Express中间件,如下所示:

//Avoid connecting to MongoDb on every request, make the connection persistant

var MongoClient = require('mongodb').MongoClient;
var options = {
  mongos: {
    ssl: false,
    sslValidate: false,
  }
};

var mongo = {
  db: null
};

MongoClient.connect(vars["MONGO_URL"], options, function(err, db) {
  if (err) {
    console.error("Error connecting to MongoDB:", err);
    process.exit(1);
  }
  mongo.db = db;
});

// Create a middleware method that will be called in request processing chain before your handler

var validateUserId = function(req, res, next) {
  var userId = req.query['userId'];
  
  // Use findOne to validate user id. It is faster and simplier
  mongo.db.collection("users").findOne({_id: userId}, {_id: 1}, function(err, record) {
    if (err) {
      return res.status(500).send("Error getting user");
    }
    if (!record) {
      return res.status(403).send("Can't figure out who you are");
    }
    next();
  });
};

然后您可以通过以下方式使用此中间件:

app.get("/performVerifiedAction", validateUserId, function(req,res){
	res.send("You may pass");
});