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

Returning data from mongo within an express.js router function

本文关键字:mongo 返回 数据 函数 js 路由器      更新时间:2023-09-26

我正在尝试编写一个简单的验证函数,该函数采用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;
};

此函数不返回任何内容。

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

这个想法是不必将此代码放入需要进行验证的每个路由中,只需在执行其他任务(不需要访问或连接到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;
});

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

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

按照 Node 中的约定.js异步函数

在其最后一个参数中接收回调,请参阅如何为 Node 编写异步函数.js

在 Node.js 样式回调之后,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); 
    }
    //...