如何让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数组:
- 创建Message Model:
export const MessageSchema = SchemaFactory.createForClass(Message); export const MessageModel = mongoose.model('Message', MessageSchema);
- 修改消息创建函数:
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
相关产品推荐
相关产品推荐

