Mongoose 和 Next.js:未处理的运行时错误 TypeError:无法读取未定义的属性(读取“令牌”)

问题描述 投票:0回答:4

我基本上定义了这个模型,就像另一个不会出错的模型一样;所以我很困惑为什么它不起作用......

这是一个最小的、可重复的示例

不工作:

import mongoose from 'mongoose';

const TokenSchema = new mongoose.Schema({
  _userId: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' },
  token: { type: String, required: true },
  createdAt: { type: Date, required: true, default: Date.now, expires: 43200 }
});




export default mongoose.models.Token || mongoose.model('Token', TokenSchema);

工作:

import mongoose from 'mongoose';
import emailValidator from 'email-validator'
import bcrypt from 'bcrypt'

import crypto from 'crypto'

const SALT_ROUNDS = 12;

const UserSchema = new mongoose.Schema(
  {
    username: {
      type: String,
      required: true,
      trim: true,
      lowercase: true,
      index: { unique: true },
      validate: {
        validator: emailValidator.validate,
        message: props => `${props.value} is not a valid email address!`
      }
    },
    password: {
      type: String,
      required: true,
      trim: true,
      index: { unique: true },
      minlength: 7,
      maxlength: 11
    },
    roles: [{ type: 'String' }],
    isVerified: { type: Boolean, default: false },
    passwordResetToken: String,
    resetPasswordExpires: Date
  },
  {
    timestamps: true
  }
);

UserSchema.pre('save', async function preSave(next) {
  const user = this;
  if (!user.isModified('password')) return next();
  try {
    const hash = await bcrypt.hash(user.password, SALT_ROUNDS);
    user.password = hash;
    return next();
  } catch (err) {
    return next(err);
  }
});

UserSchema.methods.generatePasswordReset = function () {
  this.resetPasswordToken = crypto
    .randomBytes(20)
    .toString('hex');
  this.resetPasswordExpires = Date.now() + 3600000; // expires in an hour
};

UserSchema.methods.comparePassword = async function comparePassword(candidate) {
  return bcrypt.compare(candidate, this.password);
};



export default mongoose.models.User || mongoose.model('User', UserSchema)

我也在 Next.js Examples 存储库中关注这个example

请帮忙! :)

javascript mongodb mongoose next.js mongoose-schema
4个回答
2
投票

显然,发生了

TypeError: Cannot read properties of undefined (reading 'Token')
,因为代码本来应该在服务器端执行,但它却在客户端执行。

真正发生的事情是 mongoose 尚未发起与数据库的连接,因此

mongoose.models
未定义。但解决方法不是尝试启动数据库连接:

我也遇到了类似的问题,当我试图在同一个文件中定义太多东西时,也就是说......在我的例子中,我试图定义可以拉入客户端代码的 Typescript 接口,但是猫鼬模型定义最终也会执行......

我读到 NextJS 做了相当多的工作来拆分发送到客户端的代码和保留在服务器端的代码...开发人员应该牢记这一点并尝试拆分与客户端相关的内容和服务器端到不同的文件中。

就我而言,我将接口定义和自定义 Hook 放置在与 Mongoose 架构定义不同的文件中;然后在我需要时仅导入接口和挂钩,这使得错误消失了。

尝试将所有内容放在同一个地方听起来合乎逻辑且整洁,但在这种情况下不起作用。


1
投票

我复制了你的代码,它工作得很好(进入

tokens
集合与
token
可能像预期的那样)我注意到的一件事是
expires
上的
createdAt
字段 - 这是一个 NextJS 字段吗?这不是默认字段,所以只是好奇。另外,您能否粘贴您遇到的确切错误,这将有助于其他人追踪问题。

{
  _userId: new ObjectId("5e1a0651741b255ddda996c4"),
  token: 'abcd123',
  createdAt: 2021-09-24T23:10:24.288Z,
  _id: new ObjectId("614e5ae04c741f91ac062530"),
  __v: 0
}

此外,在声明模型时请考虑使用 timestamps 选项属性,因为这将省去您设置

createdAt
的麻烦(而且您还可以让
updatedAt
自动更新)。

    token: { type: String, required: true },
  },
  {
    timestamps: true
  } 
);


1
投票

我也有同样的错误。即使我的架构文件是正确的。问题是由于某种原因,我一直在反应组件文件中导入模型

 import room from "../models/room";

0
投票

我遇到了同样的错误,并通过以下解决方案解决了。

export default mongoose.models?.User || mongoose.model('User', UserSchema)
© www.soinside.com 2019 - 2024. All rights reserved.