(node:50868) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'save' of null

(node:50868) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'save' of null

所以我试图在 discord 中制作一个简单的 XP 级系统,每次有人发送消息时它都会升级。我在我的消息事件中为我的关卡系统准备了这个。当我使用 Mongoose 时,级别被定义为它的模式。问题是它可以保存它,这个人没有数据,他们发送一条消息,它创建像 XP: 0 level: 1 这样的数据,但之后当他们发送消息给 XP: 25 等时不会再次更新。错误是(节点:50868)UnhandledPromiseRejectionWarning:TypeError:无法读取 属性 'save' of null

level1.findOne({ guildID: message.guild.id, userID: message.author.id }, async (err, res) => {
  if(err) return console.error(err)

  if(!res) {
    let newdata = new level1({
      guildID: message.guild.id,
      userID: message.author.id,
      level: 1,
      xp: 0,
      totalxp: 0,
      time: Date.now()
    })

    newdata.save()
    res = newdata
  } else {

    if (message.content.startsWith(`${prefix}`)) return;

  const generate = Math.floor(Math.random() * 18);
    (await level1.findOneAndUpdate({ guildID: message.guild.id, userID: message.guild.id }, { totalxp: res.totalxp += generate, xp: res.xp + generate, time: Date.now() })).save()

  if(res.xp >= res.level * 300) {
    (await level1.findOneAndUpdate({ guildID: message.guild.id, userID: message.guild.id }, { level: res.level++, xp: 0 })).save()
    message.channel.send(`Congratulations you are now Level **${res.level}**, ${message.author}`);
  }
}

})

您不需要将 .save() 添加到 findOneAndUpdate

findOneAndUpdate 将更新数据库中的记录而不需要使用 .save()

所以你的更新查询应该像

await level1.findOneAndUpdate(
    { guildID: message.guild.id, userID: message.guild.id }, // filter part
    { totalxp: res.totalxp += generate, xp: res.xp + generate, time: Date.now() } // update part
)

await level1.findOneAndUpdate(
    { guildID: message.guild.id, userID: message.guild.id },
    { level: res.level++, xp: 0 }
)

我认为这可以解决问题

关于代码的逻辑,我认为我们可以在更新查询之前使用一些逻辑将两个更新查询组合在一个查询中

我们可以在else部分使用这个逻辑

const generate = Math.floor(Math.random() * 18);

let updatePart = {
    totalxp: (res.totalxp || 0) + generate, // this will be updated in all cases, even if the level is upgraded or not
    time: Date.now() // this will also be updated in all cases
}

let msg = ''; // a message to be returned after the update

if (res.xp + generate >= res.level * 300) {
    // if experience + random generate is greater than level * 300, 
    // then we need to update the level, and set the xp to 0

    updatePart.level = res.level++;
    updatePart.xp = 0;

    // update the msg with the new level
    msg = `Congratulations you are now Level **${res.level++}**, ${message.author}`

} else {
    // if experience + random generate is lower than level * 300, this means the level is the same
    // then we need to update the xp only
    updatePart.xp = res.xp + generate;

    // update the msg
    msg = `Experience updated successfully`
}

// just do the update query once, 
// If we just need to update the document, 
// we can use updateOne instead of findOneAndUpdate

await level1.updateOne( // you can use findOneAndUpdate also, it's okay
    { guildID: message.guild.id, userID: message.guild.id }, // filter part
    updatePart // this is the update object
)

message.channel.send(msg);

希望对您有所帮助