Mongoose和Next.js:无法读取未定义的属性(阅读“Token”)

bihw5rsg  于 12个月前  发布在  Go
关注(0)|答案(4)|浏览(103)

我基本上定义了这个模型,就像另一个不会出错的模型一样;所以我很难理解为什么它不工作。
这是一个Minimal, Reproducible Example
不工作:

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 repo中跟踪了这个example
请帮帮忙!:)

zzoitvuj

zzoitvuj1#

显然,TypeError: Cannot read properties of undefined (reading 'Token')之所以发生,是因为代码在客户端执行,而实际上是在服务器端执行。
实际情况是mongoose没有启动到数据库的连接,所以mongoose.models是未定义的。但修复方法不是尝试启动数据库连接:
我也有类似的问题,当我试图在同一个文件中定义太多的东西时,也就是说.在我的例子中,我试图定义可以拉到客户端代码中的Typescript接口,但mongoose模型定义最终也会执行。
我读到NextJS做了相当多的工作来分割发送到客户端的代码和留在服务器端的代码......开发人员应该记住这一点,并尝试将与客户端和服务器端相关的内容分割到不同的文件中。
在我的例子中,我将接口定义和我的自定义Hooks放在与Mongoose Schema定义不同的文件中;然后在需要时只导入接口和Hooks,这使得错误消失了。
试图将所有内容保持在同一个位置听起来很合理,但在这种情况下行不通。

cdmah0mi

cdmah0mi2#

我复制了你的代码,它工作得很好(可能像预期的那样进入tokens集合与token)我注意到的一件事是createdAt上的expires字段-这是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
  } 
);

aelbi1ox

aelbi1ox3#

我有同样的错误。即使我的模式文件是正确的。问题是出于某种原因,我一直在导入React组件文件中的模型

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

字符串

gev0vcfq

gev0vcfq4#

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

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

字符串

相关问题