You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Mongoose嵌套Schema默认生成_id与时间戳并解决类型错误

问题与解决方案

问题背景

现有Mongoose的User Schema可自动生成_id、createdAt、updatedAt字段,但将Message作为嵌套结构使用时无法生效,执行消息创建函数时触发类型转换错误。

相关代码

Schema定义

export type UserDocument = HydratedDocument<User>;

@Schema({ timestamps: true, versionKey: false })
export class Message {
  @Prop()
  content: string;
}

@Schema({ timestamps: true, versionKey: false })
export class User implements UserInterface {
  @Prop()
  name: string;
  @Prop()
  email: string;
  @Prop([{ type: mongoose.Schema.Types.ObjectId, ref: 'Message' }])
  messages?: Message[];
}

export const UserSchema = SchemaFactory.createForClass(User);

消息创建函数

async createMessage() {
    const user = await this.userModel.findById('63ee4fc044d93a4f6bebf934');
    user.messages.push({ content: 'a' });
    return await user.save();
}

报错信息

Cast to ObjectId failed for value "{ content: 'a' }" (type Object) at path "messages" because of "BSONTypeError"

正常运行的用户创建函数

async createUser(createUserDto: CreateUserDto): Promise<CreatedUserDto> {
    return this.userModel.findOneAndUpdate(
      { name: createUserDto.name },
      createUserDto,
      { upsert: true, new: true },
    );
}

错误原因

当前messages字段被定义为引用Message集合的ObjectId数组,但代码中直接推送了一个包含content的普通对象,而非已保存Message文档的ObjectId,导致Mongoose无法将该对象转换为合法的ObjectId,触发类型错误。同时,若你期望Message作为嵌套子文档嵌入User,当前的引用式定义不符合需求。

解决方案

方案1:嵌入式子文档(推荐,符合嵌套需求)

若希望Message直接嵌入User文档,无需独立集合,修改User的messages字段定义:

@Schema({ timestamps: true, versionKey: false })
export class Message {
  @Prop()
  content: string;
}

@Schema({ timestamps: true, versionKey: false })
export class User implements UserInterface {
  @Prop()
  name: string;
  @Prop()
  email: string;
  // 直接传入Message类,定义为子文档数组
  @Prop({ type: [Message] })
  messages?: Message[];
}

export const UserSchema = SchemaFactory.createForClass(User);

修改后,执行createMessage函数时,推送的对象会被自动处理为Mongoose子文档,自动生成_id、createdAt、updatedAt字段,最终嵌入到User文档的messages数组中。

方案2:引用式(Message独立存储)

若需Message作为独立集合,需先创建并保存Message文档,再将其ObjectId添加到User的messages数组:

  1. 创建Message Model:
export const MessageSchema = SchemaFactory.createForClass(Message);
export const MessageModel = mongoose.model('Message', MessageSchema);
  1. 修改消息创建函数:
async createMessage() {
    // 先创建并保存Message文档
    const newMessage = new this.messageModel({ content: 'a' });
    await newMessage.save();
    
    // 将Message的_id添加到用户的messages数组
    const user = await this.userModel.findById('63ee4fc044d93a4f6bebf934');
    user.messages.push(newMessage._id);
    return await user.save();
}

此方式下,Message单独存储在自身集合,User仅保存对应ObjectId,查询时需使用populate方法获取完整Message数据。

内容的提问来源于stack exchange,提问作者Romik romikromik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:06:26