无法从函数中调用mongodb方法

时间:2016-01-09 16:42:20

标签: javascript angularjs mongodb function database

所以我做了一个用户登录,数据库是mongodb,它完美无缺。但是,我想在人登录后再次调用mongodb,所以我决定将其拆分为单独的函数。但是,当我尝试使用登录脚本并将其转入函数时,数据库将无法打开。这是没有意义的,因为我使用完全相同的代码在路线内工作。这可以在一个函数中完成吗?有谁知道发生了什么?

以下是调试器的代码和图像,证明dB不会打开。

路线

   // Listen for Upload file 
    router.post('/uploadFile', function (req, res) {
        upload(req, res, function (err) {
            if (err) {
                console.log("Error uploading file");
            } else {
                //var databaseName = "E-learn", collection = "Accounts";
                var username = req.body.username ; 
                var fileName = req.file.filename ; 
                var filePath = req.file.path ; 
                console.log(username);
                console.log("GET " + req.file.fieldname);
                console.log("GET " + req.file.filename);
                console.log("GET " + req.file.orignalName);
                console.log("GET " + req.file.path);
                var result = findOne(username); 
                res.json(result); 
            }
        });
    });

函数调用

function findOne(username){
    var databaseName = "E-learn", collection = "Accounts";
    var db = new Db(databaseName, new Server('localhost', 27017));
    db.open(function (err, db) {
        console.log(databaseName + ": opened");
        console.log(db);
        db.collection(collection).findOne({username:username}, function (err, doc) {
            assert.equal(null, err);
            if (doc != null) {
                console.log("Found");
                // db.close();
                return "Found" ; 

            } else {
                console.log("Not Found");
                // db.close();
                return "Not found";
            }
            db.close();
        });
    });
console.log("Did not open")
db.close(); 
return 0 ; // Should not be called
}

enter image description here enter image description here

3 个答案:

答案 0 :(得分:0)

首次查看时,您的代码中存在几个问题。

  1. 在异步函数中使用return来返回结果将不起作用。 您需要定义一个回调函数,您将其作为findOne的引用传递。需要调用此回调函数以返回结果。

  2. 在此方案中打印“未打开”并不意味着数据库未打开。这是异步执行,因此数据库可能会在打印完该控制台日志后打开。

答案 1 :(得分:0)

不确定您正在运行的ES版本,但如果您想采用同步方法,请尝试使用此版本的findOne。 Async / Await使异步代码同步。

async function findOne(username){
    var databaseName = "E-learn", collection = "Accounts";
    var db = new Db(databaseName, new Server('localhost', 27017));

    let db = await db.open();
    // try above line first
    //let {err, db} = await db.open();

    let doc = await db.collection(collection).findOne({username:username});
    // try above line first
    //let {err, doc} = await db.collection(collection).findOne({username:username});

    //assert.equal(null, err);
    if (doc != null) {
        console.log("Found");
        // db.close();
        return "Found" ; 

    } else {
        console.log("Not Found");
        // db.close();
        return "Not found";
    }
    db.close();

//console.log("Did not open")
//db.close(); 
//return 0 ; // Should not be called
}

如果Async / Await出现错误,请尝试安装此软件包。 https://www.npmjs.com/package/asyncawait

答案 2 :(得分:0)

您正面临大多数新引入的JavaScript开发人员遇到的典型异步回调问题。

首先,JavaScript is asynchronous(必须为您阅读)。这意味着当您将函数作为某个参数传递时,您不能指望函数内部的代码将内联到代码中。也许您传递的函数将作为事件的结果被调用(连接到某个东西,用户单击按钮,数据库被打开...),因此将来某个时候会发生。即使是1纳秒之后,也将在未来。

所以你希望它以这种方式运行:

function findOne(username){
    // Start with this (step 1)
    var databaseName = "E-learn", collection = "Accounts";
    // Then continue with this (step 2)
    var db = new Db(databaseName, new Server('localhost', 27017));
    // Open the database (step 3) and the code will wait for the database to open
    db.open(function (err, db) {
        // Run this inline, just after db.open (step 4)
        console.log("OPEN");
        [...]
    });
    // Continue with this after the database was open (step 5)
    console.log("Did not open")
    db.close(); 
    return 0 ; // Should not be called
}

但实际上发生的事情是:

function findOne(username){
    // Start with this (step 1)
    var databaseName = "E-learn", collection = "Accounts";
    // Then continue with this (step 2)
    var db = new Db(databaseName, new Server('localhost', 27017));
    // Open the database (step 3), pass a function that will be called by the database when is open AND continue with the next step
    db.open(function (err, db) {
        // This function will be called when the database is open, so right now is not called.
        console.log("OPEN");
        [...]
    });
    // This is the next step after step 3 (step 4).
    console.log("Did not open")
    db.close(); 
    return 0 ; // Should not be called
}

// And sometime in the future you suddenly get in console OPEN, when the database decides to run the callback you passed to it.

另一种研究方法是return将始终从函数返回,因此具有此嵌套函数:

function findOne(username) { // function keyword, so this is a function (number 1)
    [...]
    db.open(function (err, db) { // Note the function keyword here, so this is a function too (number 2)
        [...]
        return 1; // This return actually works, BUT affects the function where it belongs, which is function number 2 in this case.
    });
    [...]
    return 0; // And this one is the return of the function number 1.
}

因此,假设db.open在运行下一行代码之前立即运行回调。虽然它不是以异步方式运行,但回调中的return仍然无法返回findOne函数。

异步问题需要异步解决方案。 (或者使用ES6生成器(异步,等待等等),但是目前会让你更加复杂,因为你仍然不知道代码会发生什么,更糟糕的是,何时使用生成器(因为它们被束缚)到异步回调),所以最好先了解JS中的异步回调。当你理解它时,实际上很容易。只是一些变化:

// Listen for Upload file
router.post('/uploadFile', function (req, res) {
    upload(req, res, function (err) {
        if (err) {
            console.log("Error uploading file");
        } else {
            //var databaseName = "E-learn", collection = "Accounts";
            var username = req.body.username ; 
            var fileName = req.file.filename ; 
            var filePath = req.file.path ; 
            console.log(username);
            console.log("GET " + req.file.fieldname);
            console.log("GET " + req.file.filename);
            console.log("GET " + req.file.orignalName);
            console.log("GET " + req.file.path);
            // Converted the sync function to an async one, by passing a
            // callback function as a parameter with 2 arguments, being
            // the first the possible error and the second the data
            findOne(username, function(err, result) {
                if (err) {
                    console.log("Error uploading file");
                } else {
                    res.json(result);
                }
            });
        }
    });
});

// Here you can see now that we have the callback parameter,
// that references the callback function we passed before and
// we can call it whenever we want
function findOne(username, callback) {
    var databaseName = "E-learn", collection = "Accounts";
    var db = new Db(databaseName, new Server('localhost', 27017));
    db.open(function (err, db) {
        if (err) {
            callback(err); // If error, pass the error as first argument of the callback
        } else {
            console.log(databaseName + ": opened");
            console.log(db);
            db.collection(collection).findOne({username:username}, function (err, doc) {
                if (err) {
                    callback(err); // As findOne is another async callback too, the same as above. Check for err
                } else {
                    // And if everything is fine, then pass the result as the second parameter of the callback
                    if (doc != null) {
                        callback(null, "Found");
                    } else {
                        callback(null, "Not found");
                    }
                }
                db.close();
            });
        }
    });
}

您可能已经注意到,您在数据库方法和路由器方法内部传递了大量function作为回调。

一些开发人员说:

  • 现在只需逐行阅读代码,并尝试了解每个代码的发生情况。通过这种方式,您可能会想到"为什么我写的代码不是由回调制作的,而不是我的?"。这个问题和一些研究将对你有很大帮助。
  • 始终有干净的缩进。您的代码有一些问题。缩进是JavaScript必须的,因为它具有异步特性,你可以拥有一个回调地狱,并且缩进对它有很大帮助。