提问者:小点点

使用Node.js,Mongoose和Discord.js的未定义错误[无法读取未定义的属性]


我一直在寻找类似的问题,但似乎还没有找到一个对我来说很有效的解决方案。所以我正在开发一个Discord bot,它从MongoDB数据库中获取数据,并使用Mongoose以Discord嵌入消息的形式显示这些数据。大多数情况下,一切都很好,但是我的代码中有一小段给我带来了麻烦。所以我需要导入所有可用用户和每个用户的“时间”数据的数组。下面是我用来导入上述数据的代码块:

for (i = 0;i < totalObj; i++){
    timeArray[i] = await getData('time', i);
    userArray[i] = await getData('user', i);
}

这个for循环引用了我制作的一个名为getData的函数,它通过以下方法从MongoDB获取数据:

async function getData(field, value){
var data;
await stats.find({}, function(err, result){
    if(err){
        result.send(err);
    }else{
        data = result[value];
    }
});

if(field == "user"){
    return data.user;
}else if (field == "time"){
    return data.time;
}else{
    return 0;
}

所以for循环就是我当前的错误所在。当我试图运行此代码并通过discord消息显示我的数据时,我会收到此错误并且消息没有被发送:

(节点:13936)UnhandledPromiserEjectionWarning:TypeError:无法读取未定义的属性“time”

现在奇怪的是,这种错误并不是每次都发生的。如果我继续调用从我的discord服务器触发这段代码的命令,如果命令实际上显示了消息或给出了这个错误,这几乎就像是一个50/50的机会。很不一致。

这个错误使我感到困惑,因为未定义的部分对我来说没有意义。在mongoDB集合中搜索的对象是明确定义的,for循环从不超过存在的对象数。我唯一的结论是,我的异步函数设计出了问题。我曾尝试修改代码,减少使用getData函数的次数,或者根本不使用等待或异步设计,但这留下了最后的不一致消息,其中包括几个未定义的变量和最终的崩溃。

如果任何人有任何意见或建议,那将非常感谢。仅供参考,下面是接收数据,对其进行排序并准备一个字符串以显示在discord服务器上的完整函数(尽管错误似乎只出现在第一个for循环中):

async function buildString(){
var string = "";
var totalObj;
var timeArray = [];
var userArray = [];
var stopSort = false;

await stats.find({}, function(err, result){
    if(err){
        result.send(err);
    }else{
        totalObj = result.length;
    }
});

for (i = 0;i < totalObj; i++){
    timeArray[i] = await getData('time', i);
    userArray[i] = await getData('user', i);
}

while(!stopSort){
    var keepSorting = false;
    for(i = 0; i < totalObj ; i++){
        var target = await convertTime(timeArray[i]);
        for(j = i + 1 ; j < totalObj ; j++){
            var comparison = await convertTime(timeArray[j]);
            if(target > comparison){

                //Switch target time with comparison time so that the lower time is up front
                var temp = timeArray[i];
                timeArray[i] = timeArray[j];
                timeArray[j] = temp;

                //Then switch the users around so that the user always corresponds with their time
                var userTemp = userArray[i];
                userArray[i] = userArray[j];
                userArray[j] = userTemp;

                //The loop will continue if even a single switch is made
                keepSorting = true;
            }
        }
    }

    if(!keepSorting){
        stopSort = true;
    }
}

//String building starts here
var placeArray = [':first_place: **1st', ':second_place: **2nd', ':third_place: **3rd', '**4th', '**5th', '**6th', '**7th', '**8th', '**9th', '**10th'];
for(i = 0; i < totalObj; i++){
    string = await string.concat(placeArray[i] + ": " + userArray[i] + "** - " + timeArray[i] + " \n\n");
    console.log('butt');
}


console.log("This String:" + string);
return string;

}


共1个答案

匿名用户

我认为问题是您试图用回调await函数,它将不工作=>;对data.time的访问可能在data=result[value]之前运行。如果需要等待回调,可以使用自定义promise(或使用util.promisify,此处提供更多信息)

承诺:

function findStats(options) {
        return new Promise((resolve, reject) => {
            return stats.find(options, function (err, result) {
                if (err) {
                    return reject(err)
                }
                return resolve(result)
            })
        })
    }

用途。允诺

const util = require('util');
const findStats = util.promisify(stats.find);

现在可以在函数中使用await

async function getData(field, value) {
    try {
        const result = await findStats({})
        const data = result.value

        if (field === 'user') {
            return data.user
        }
        if (field === 'time') {
            return data.time
        }
        return 0
    } catch (error) {
        // here process error the way you like
        // or remove try-catch block and sanitize error in your wrap function
    }
}