使用Mongoose/Typegoose时传入字符串ObjectId生成新ID而非原ID的问题求助
看起来你遇到的核心问题是:当尝试将客户端传入的ID字符串转换为ObjectId时,得到的不是原ID对应的ObjectId,而是全新生成的。结合你的描述和示例,我来帮你排查可能的原因并给出解决方案:
1. 首先检查传入的ID格式是否有效
MongoDB的ObjectId要求是24位十六进制字符串,看你给出的输入参数:
{"channelId":"614728ed7f88e836fcc22827","senderId":"61471fdb6cb0b1129b8b7316","contents":""}
这里的senderId是61471fdb6cb0b1129b8b7316,数一下字符数是25位!这明显不符合ObjectId的格式要求。当你传入无效的ObjectId字符串时,Mongoose在某些情况下不会抛出错误,而是自动生成一个新的ObjectId来替代——这正是你看到的现象。
你可以用Mongoose自带的验证方法先检查ID有效性:
import { Types } from 'mongoose'; console.log(Types.ObjectId.isValid("61471fdb6cb0b1129b8b7316")); // 会返回false
2. 确认你的Typegoose Schema定义正确
如果Schema中没有正确指定字段类型为ObjectId,Mongoose可能会把这些字段当成需要自动生成ID的字段。请检查你的Message类定义,确保senderId和channelId的@Prop配置正确:
import { prop, getModelForClass } from '@typegoose/typegoose'; import { Types } from 'mongoose'; class Message { // 必须指定type为Types.ObjectId,确保Mongoose识别为引用ID而非自增ID @prop({ type: Types.ObjectId, required: true }) senderId!: Types.ObjectId; @prop({ type: Types.ObjectId, required: true }) channelId!: Types.ObjectId; @prop() contents!: string; } const MessageModel = getModelForClass(Message);
特别注意:不要给这些字段设置default: () => new Types.ObjectId(),否则即使你传入了值,也会被默认值覆盖生成新ID。
3. 确保Mongoose的验证机制开启
默认情况下Mongoose会在保存前验证字段,但如果你的Model配置关闭了validateBeforeSave,无效的ID就不会被拦截。创建Model时可以显式开启验证:
const MessageModel = getModelForClass(Message, { schemaOptions: { validateBeforeSave: true } });
这样当传入无效ID时,Mongoose会抛出验证错误,而不是悄悄生成新ID。
4. 手动转换时先验证再转换
在创建文档前,先对客户端传入的ID进行有效性校验,避免无效ID流入:
async function createMessage(message: { senderId: string; channelId: string; contents: string }) { // 先验证两个ID的有效性 if (!Types.ObjectId.isValid(message.senderId)) { throw new Error("Invalid senderId: must be a 24-character hex string"); } if (!Types.ObjectId.isValid(message.channelId)) { throw new Error("Invalid channelId: must be a 24-character hex string"); } const model = await MessageModel.create({ senderId: new Types.ObjectId(message.senderId), channelId: new Types.ObjectId(message.channelId), contents: message.contents, }); return model; }
总结
你遇到的问题最可能的原因是传入的senderId格式错误(25位而非24位),导致Mongoose无法解析为有效ObjectId,进而自动生成新ID。先修正客户端传入的ID格式,再结合上述Schema配置和验证步骤,就能解决这个问题。
内容的提问来源于stack exchange,提问作者Nikola-Milovic

