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

Posted

技术标签:

【中文标题】使用 Node.js、Mongoose 和 Discord.js 的未定义错误 [无法读取未定义的属性]【英文标题】:Undefined errors using Node.js, Mongoose, and Discord.js [Cannot read property of undefined] 【发布时间】:2021-01-08 05:11:31 【问题描述】:

我一直在寻找类似的问题,但似乎还没有找到适合我的解决方案。所以我正在开发一个 Discord 机器人,它从 MongoDB 数据库中获取数据,并使用 Mongoose 以不和谐嵌入消息的形式显示所述数据。在大多数情况下,一切正常,但是我的代码的一小部分给我带来了麻烦。 所以我需要导入所有可用用户的数组和每个用户的“时间”数据。这是我用来导入所述数据的代码块:

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 循环是我当前的错误所在。当我尝试运行此代码并通过不和谐消息显示我的数据时,我收到此错误并且消息未发送:

(node:13936) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'time' of undefined

现在奇怪的是,这个错误并不是每次都会发生。如果我继续从我的不和谐服务器调用触发此代码的命令,如果该命令实际显示消息或给出此错误,那几乎就像是 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,更多信息here)

承诺:

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

utils.promisify

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
    

【讨论】:

非常感谢,通过使用自定义承诺策略,程序现在可以完美运行!

以上是关于使用 Node.js、Mongoose 和 Discord.js 的未定义错误 [无法读取未定义的属性]的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mongoose、Node.js 和 Underscore 生成代码的简单方法?

单个node.js项目中的Mongoose和多个数据库

单个node.js项目中的Mongoose和多个数据库

如何让 node.js 使用 mongoose 连接到 mongolab

使用 Node.js 和 Mongoose 将查询结果保存到模型/模式的属性

如何使用 Node.js、Express 和 Mongoose 进行身份验证?