【问题标题】:Return MongoDB query result as variable instead of to console将 MongoDB 查询结果作为变量返回而不是控制台
【发布时间】:2020-03-12 22:35:46
【问题描述】:

在一个名为 db_to_var.js 的 javascript 文件中,我有以下函数可以成功地将查询返回的数组打印到数据库 test_dbconsole.log() 。 (例如,一个名为 cars 的数据库有一个键 name 描述了品牌名称,例如 toyota, hyunday,volvo。)。该方法使用:console.log("listCars function call="+listCars()); 调用并包含:

function listCars() { 
    car_and_name_grandparent = MongoClient.connect(url, function(err, db) {
        if (err) throw err;
        var dbo = db.db("testdb");

        car_and_name_parent = dbo.collection("cars").find({}, { projection: { _id: 0, name: 1} }).toArray(function(err, result) {
            if (err) throw err;
            car_and_name = result;
            db.close();

            console.log("car_and_name="+car_and_name);
            return car_and_name;
        });

        return car_and_name_parent;
    });

    return car_and_name_grandparent;
}; 

但是,car_and_name_parent 仍未定义,因为正确填充的car_and_name 实际上并未返回到car_and_name_parent。这促使我进行调查,并调查了:

  1. The documentation of .toArray(),首先不应该接受参数。因此,我检查了dbo.collection("cars").find({}, { projection: { _id: 0, name: 1} }).toArray() 实际返回的内容,即[object Promise]

    1.a 不能直接评估Promise,但必须使用thenawaitasync

    1.b 我能够将Promise 转换为function then() { [native code] } 使用.then,但我还没有找到如何进一步评估这个 从“[native code]”中检索列表的表达式。这 await 返回错误 SyntaxError: await is only valid in async function,而 async car_and_name.then 返回错误 SyntaxError: Unexpected identifier.

  2. 我还尝试将名为 carNames 的全局变量传递给函数,并将其赋值为 car_and_name,但我目前无法成功地将全局变量传递给 .toArray(..) 中的 @当我在那个位置这样做时,987654351@ 是未定义的。

如何将car_and_name 变量返回到函数listCars() 之外的变量?

【问题讨论】:

    标签: javascript mongodb promise return-value native-code


    【解决方案1】:

    以下是使用异步等待的方法。

    async function listCars() {
        let db = await MongoClient.connect(url);
        let dbo = db.db("testdb");
        return await dbo.collection("cars").find({}, { projection: { _id: 0, name: 1} }).toArray()
    }
    
    listCars().then(cars => {
        console.log(cars); //You will get your results here
    })
    

    nodejs 中的 mongoDB 查询像上面这样是异步的,所以你不能直接在变量中获取返回值。您要么必须使用回调函数,要么必须使用 .then() 才能使用上例中的 Promise。

    您使用的 toArray() 函数是一种 MongoDB 方法,您在问题中提到的方法是 jQuery 方法。这是供您参考的正确文档 -> https://docs.mongodb.com/manual/reference/method/cursor.toArray/

    希望对你有帮助!

    【讨论】:

    • 感谢您的澄清,特别是我提到了错误的语言文档。我的意图是从另一个文件app.js 调用/检索var globalVar,但我将重新实现该调用/检索以使用您给定的解决方案,因为似乎无法将数据作为全局变量获取。非常感谢您的解释!
    【解决方案2】:

    您的方法正在进行一个异步调用,该调用在检索到您要查找的值之前立即作为 Promise 执行。

    我建议将您的方法包装在一个承诺中。

    function listCars() { 
        return new Promise((resolve, reject) => {
           MongoClient.connect(url, function(err, db) {
            if (err) reject(err);
            var dbo = db.db("testdb");
    
            dbo.collection("cars").find({}, { projection: { _id: 0, name: 1} }).toArray(function(err, result) {
                if (err) reject(err);
                db.close();
                resolve(result);
            });
        });
      })
    };
    

    然后你可以这样使用它。

    listCars()
        .then(carNames => {
            // Use your variable here.
        })
        .catch(err => throw err);
    

    您也可以像这样在异步方法中使用 listCars 作为辅助方法。

    const carWork = async function() {
        try {
           const carNames = await listCars();
           // ....
        } catch (err) {
            throw err;
        }
    }
    

    【讨论】:

    • 非常感谢您的示例和解释。看来我不应该想要一个带有汽车名称列表的单独变量。既然你的回答也是,在函数listCars的属性then内部有一个lambda函数里面的变量,它接受输入carnames并且什么都不返回。这让我想知道是否有可能/希望将查询的内容作为全局变量,是吗?阅读@twjs 的答案,似乎不可能/不可取。
    【解决方案3】:

    您可以使用异步/等待。但是你没有正确使用它。您收到语法错误,表明您只能在异步函数中使用 await。所以你可以这样写你的代码,

    async function listCars() { 
     try{
        db = await MongoClient.connect(url);
        var dbo = db.db("testdb");
        car_and_name_parent = await dbo.collection("cars").find({}, { 
          projection: { _id: 0, name: 1} }).toArray();
       return car_and_name_parent
    }catch(err){
      throw err;
     }
    }; 
    

    【讨论】:

    • 非常感谢您的快速回复,我尝试使用var globalVar = listCars();var globalVar = eval(listCars()); 调用它,返回:Promise { <pending> }。也许您可以扩展您的示例,说明如何使用它?
    • 用法:var globalVar = await listCars();这直接将汽车名称列表分配给 globalVar。
    • 感谢您的建议,它会抛出:SyntaxError: await is only valid in async function。尽管如此,我同意你的观点,listCars() 绝对看起来像一个异步函数。 (为了完整性:我将您的答案和评论逐字复制粘贴了 3 次,以确保我没有复制粘贴错误。)
    • 正如我已经提到的,await 只能在异步方法内部使用,以便从任何异步块调用 listCars。否则,您可以将它与 promise 一起使用, listCars().then((list) => { var globalVar = list; }).catch(err){ // 处理错误。 }
    猜你喜欢
    • 2011-03-09
    • 2016-01-03
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多