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 条目。 如您所见,您有_idid 字段。您是否只想要单个 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?

如何在 Nestjs 中创建 mongodb 连接提供程序

NestJS - 如何自我引用 mongoDB 架构 @nestjs/mongoose?

无法将 MongoDB 与 NestJS ( Docker ) 连接