如何根据另一个查询的结果执行查询? (快递,NodeJS,mysql)

How can I execute a query based on the result of another query? (Express, NodeJS, mysql)

我正在尝试在对我的 'generateSession' 端点进行 API 调用时生成会话 ID。我想确保我没有任何重复的会话 ID,因此我查询数据库以检查生成的 ID 是否匹配。如果不匹配,则 ID 有效,我进行第二次查询以添加具有所述会话 ID 的活动用户。

尽管我执行了第一个查询,但 'id_is_valid' 布尔值从未设置为 true,因此我的程序陷入了 while 循环。

我是 JavaScript 的新手,但根据一些研究,我很确定问题是由于数据库调用的异步性质造成的。但是,我不确定从那里去哪里。有更多 js 知识的人可以给我一些指导吗?

谢谢!

var express = require('express');
var router = express.Router();

var myDB = require('../db-connection');

function generateSession() {
    var session_id = '';
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (var i = 0; i < 30; i++) session_id += possible.charAt(Math.floor(Math.random() * possible.length));

    return session_id;
}

router.get('/generateSession', function(req, res){
    var session_id = '';
    var id_is_valid = false;
    while (!id_is_valid){
        session_id = generateSession();

        myDB.query("SELECT * FROM activeUser WHERE session_id = ?", [session_id], function(error, results, field){
            if(error) throw error;
            else{
                if (results.length === 0) is_is_valid = true;
            }
        });
    }

    myDB.query("INSERT INTO activeUser (is_registered, session_id) VALUES (0, ?)", [session_id], function(error, results, fields){
        if (error) res.send('{"success": false}');
        else res.send('{"success": true, "session_id": "' + session_id + '"}');
    });
});

根据我对您的代码的了解,您要做的基本上是为具有唯一会话 ID 的登录用户创建一个新的用户会话,同时确保该会话 ID 不存在于集合中.

因此,解决此问题的方法是首先查询以检查会话 ID 是否已存在于 Active_Users 集合中,如果不存在,则进行保存调用以使用生成的会话 ID 保存用户。

var express = require('express');
var router = express.Router();

var myDB = require('../db-connection');

function generateSession() {
    var session_id = '';
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (var i = 0; i < 30; i++) session_id += possible.charAt(Math.floor(Math.random() * possible.length));

    return session_id;
}

router.get('/generateSession', function(req, res) {
    var session_id = '';

    myDB.query("SELECT * FROM activeUser WHERE session_id = ?", [session_id], function(error, results, field) {
        if (error) {
            throw error;
        } else {
            if (results.length === 0) {
                //if session id is not present , insert new user
                session_id = generateSession();
                myDB.query("INSERT INTO activeUser (is_registered, session_id) VALUES (0, ?)", [session_id], function(error, results, fields) {
                    if (error) res.send('{"success": false}');
                    else res.send('{"success": true, "session_id": "' + session_id + '"}');
                });
            }
            //else do nothing or inser nothing
        }
    });

});

但理想情况下,如果您每次向 /generate 会话发出请求时都生成一个真正随机的会话 ID,是否真的有必要检查集合中的重复项。 现在,如果生成随机 ID 的逻辑不完美,您始终可以使用像 shortId 这样的模块来为您完成这项工作。这将避免不必要的数据库调用并节省性能,您的代码将更加整洁。

Although my first query executes, the id_is_valid boolean never gets set to true so my program gets stuck in the while loop.

这是因为数据库调用本质上是异步的。如果你运行下面的程序你就知道了。

'use strict';

let id_is_valid = false;
let count = 0;

while (!id_is_valid) {
  count++;
  console.log(`No of time setTimeout Invoked ${count}`);
  setTimeout(function() { // simulating a db call that takes a second for execution
    id_is_valid = true;
  }, 1000);
}

console.log('This line wont be printed');

输出

No of time setTimeout Invoked 61415
No of time setTimeout Invoked 61416
No of time setTimeout Invoked 61417
^C //I killed it.

与 damitj07 一样,我也建议使用像 shortId 这样的 npms 来唯一生成 sessionId。这将帮助您消除数据库调用。 但是,如果您的业务逻辑受到限制并且您需要以您编写的当前方式使用它。我想我们可以使用 async & await

'use strict';

let isFound = false;
let count = 0;

function doDbQuery() {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      resolve(true);
    }, 2000);
  });
}

async function run() {
  while (!isFound) {
    count++;
    console.log(`No of time setTimeout Invoked ${count}`);
    isFound = await doDbQuery();
  }
  console.log('This line WILL BE printed');
}

run();

输出

No of time setTimeout Invoked 1
This line WILL BE printed

对您的代码进行这些更改,

router.get('/generateSession', async function (req, res) {
  var session_id = '';
  var id_is_valid = false;
  while (!id_is_valid) {
    session_id = generateSession();
    id_is_valid = await checkSessionIdInDb(session_id);
  }

  myDB.query('INSERT INTO activeUser (is_registered, session_id) VALUES (0, ?)', [session_id], function (error, results, fields) {
    if (error) {
      res.send('{"success": false}');
    } else {
      res.send('{"success": true, "session_id": "' + session_id + '"}');
    }
  });
});

function checkSessionIdInDb() {
  return new Promise((resolve, reject) => {
    myDB.query('SELECT * FROM activeUser WHERE session_id = ?', [session_id], function (error, results, field) {
      if (error) {
        return reject(error);
      } else {
        if (results.length === 0) {
          resolve(true);
        }
        resolve(false);
      }
    });
  });