NestJS 和 MongoDB | CastError:模型“Player”的路径“_id”处的值“1”转换为 ObjectId 失败
Posted
技术标签:
【中文标题】NestJS 和 MongoDB | CastError:模型“Player”的路径“_id”处的值“1”转换为 ObjectId 失败【英文标题】:NestJS & MongoDB | CastError: Cast to ObjectId failed for value "1" at path "_id" for model "Player" 【发布时间】:2020-06-28 08:26:22 【问题描述】:我目前正在实现一个演示应用程序,以了解带有 mongoDB 的 NestJS 框架。
我目前面临以下错误消息,我无法修复:
模型“Player”的路径“_id”处的值“1”失败 + 40997ms CastError:在路径“_id”的值“1”中转换为 ObjectId 失败 模型“播放器”
我的控制器如下所示:
@Controller('/players')
export class PlayersController
constructor(private playersService: PlayersService)
@Get('/:id')
async getPlayer(@Res() res, @Param('id') id: number)
const player = await this.playersService.getPlayer(id);
if (!player) throw new NotFoundException('Player does not exist!');
return res.status(HttpStatus.OK).json(player);
我的服务如下所示:
@Injectable()
export class PlayersService
constructor(@InjectModel('Player') private readonly playerModel: Model<Player>)
async getPlayer(playerId: number): Promise<Player | undefined>
const player = await this.playerModel.findById(playerId);
return player;
我的 DTO 如下所示:
export class CreatePlayerDto
readonly id: number;
readonly name: string;
readonly score: number;
readonly created_at: Date;
readonly is_deleted: boolean;
我的模型如下所示:
export class Player extends Document
readonly id: number;
readonly name: string;
readonly score: number;
@Exclude() readonly createdAt: Date;
@Exclude() readonly isDeleted: boolean;
我的猫鼬模式如下所示:
export const PlayerSchema = new mongoose.Schema(
id: Number,
name: String,
score: Number,
createdAt: type: Date, default: Date.now ,
isDeleted: Boolean
);
键入 db.players.find() 后的示例 mongoDB 条目
"_id" : ObjectId("5e5fccac9d16bf2d325cd57a"), "id" : 1, "name" : "Player One", "score" : 0, "createdAt" : "2020-04-03", "isDeleted" : false
我在这里做错了什么或者我该如何解决这个错误?
【问题讨论】:
尝试改变猫鼬模式_id: Number,
@Valijon 不,不起作用。我更新了我的问题并添加了一个示例 mongoDB 条目。
如您所见,您有_id
和id
字段。您是否只想要单个 id
字段作为 PK wchich 应该是数字? .findById
按 _id
字段搜索,在这种情况下预期 ObjectId
【参考方案1】:
为什么会出现错误:
在服务中,您有这段代码试图从数据库中查找播放器文档:this.playerModel.findById(playerId);
该查询中playerId
的值是一个字符串(或转换后的数字),但是,猫鼬方法model.findById
在内部执行如下操作:this.playerModel.find( _id: playerId );
并从您添加到的示例数据库输出中问题,您可以看到 _id 是 ObjectId 而不是字符串或数字,因此您会收到错误 CastError: Cast to ObjectId failed for value “1” at path “_id” for model “Player”
修复:
您可以做两件事:
1. 更新查询以使用 id 而不是 _id。您的查询将是这样的:this.playerModel.find( id: playerId );
2. 更新您的架构,使 _id 属性是一个数字,而不是 ObjectID(默认值)。如果这样做,则必须确保 _id 值的唯一性。如果您这样做,您的查询将不需要更改。您的架构将是这样的:
export const PlayerSchema = new mongoose.Schema(
_id: Number,
name: String,
score: Number,
createdAt: type: Date, default: Date.now ,
isDeleted: Boolean
);
如果 _id 字段没有硬性要求,您可以使用 ObjectId 值而不是 Number,这样可以省去确保 _id 字段唯一性的压力。为此,请在架构中将 _id 属性设置为 _id: mongoose.ObjectId
。
您还需要更新 dto、模型和您输入播放器对象的所有其他位置以反映架构更新,即添加具有不同类型的“_id”属性,可能删除前“id”属性。
如果您想知道 _id 字段是如何到达那里的;它是每个 MongoDB 文档的属性,用作主键。即使您没有将它添加到您的架构中,MongoDB 驱动程序(在本例中为 mongoose)或 mongod 服务器也会为您添加它。更多详情here
【讨论】:
感谢您的详细回答。我现在了解错误的原因。但是如何更新我的猫鼬模式?我没有在我的架构中定义“_id”(见上文)。这是由 mongoDB 自动创建的(除了我的“id”属性)。 我刚刚在答案中添加了更新后的架构。 再次强调一下,如果您要为 _id 属性使用数字值,则必须确保 _id 值在整个集合中是唯一的,即如果文档的 _id 已经为 1,该集合中的任何其他文档都不能具有该 _id 值,否则会出现错误。 有没有办法使用ObjectId类型的_id来保证唯一性?这种方式行不通。使用建议的 schama,在向 /players 发出 GET 请求并重新加载页面后,响应中没有 _id 会发生节点错误:错误 [ERR_INTERNAL_ASSERTION]:这是由 Node.js 中的错误或 Node 的错误使用引起的.js 内部结构。请在github.com/nodejs/node/issues 中打开此堆栈跟踪的问题 ..我的模型和 dto 呢?我是否也需要更改它们?以上是关于NestJS 和 MongoDB | CastError:模型“Player”的路径“_id”处的值“1”转换为 ObjectId 失败的主要内容,如果未能解决你的问题,请参考以下文章
在 NestJS 中使用 Jest 和 MongoDB 进行单元测试
NestJS TypeORM MongoDB 无法使用 find 或 FindOne 搜索存储库
如何使用nestJS将文件上传到mongoose上的mongodb?