I am currently implementing a demo application to get to know the NestJS framework with mongoDB.
I am currently facing the following error message, which I cannot fix:
failed for value "1" at path "_id" for model "Player" + 40997ms CastError: Cast to ObjectId failed for value "1" at path "_id" for model "Player"
My controller looks like this:
@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);
}
}
My service looks like this:
@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;
}
}
My DTO looks like this:
export class CreatePlayerDto {
readonly id: number;
readonly name: string;
readonly score: number;
readonly created_at: Date;
readonly is_deleted: boolean;
}
My model looks like this:
export class Player extends Document {
readonly id: number;
readonly name: string;
readonly score: number;
@Exclude() readonly createdAt: Date;
@Exclude() readonly isDeleted: boolean;
}
My mongoose schema looks like this:
export const PlayerSchema = new mongoose.Schema({
id: Number,
name: String,
score: Number,
createdAt: { type: Date, default: Date.now },
isDeleted: Boolean
});
Example mongoDB entry after typing db.players.find()
{ "_id" : ObjectId("5e5fccac9d16bf2d325cd57a"), "id" : 1, "name" : "Player One", "score" : 0, "createdAt" : "2020-04-03", "isDeleted" : false }
What am I doing wrong here or how can I fix this Error?
Why you are having the error:
In the service, you have this piece of code that is attempting to find a player document from the DB: this.playerModel.findById(playerId);
The value of the playerId
in that query is a string(or number after casting), however, the mongoose method model.findById
internally is doing something like this: this.playerModel.find({ _id: playerId });
and from the sample DB output you added to the question, you can see that _id is an ObjectId not a string or number, consequently you get the error CastError: Cast to ObjectId failed for value “1” at path “_id” for model “Player”
The fix:
There are two things you can do:
1. Update the query to use id instead of _id. You query would then be something like this: this.playerModel.find({ id: playerId });
2. Update your schema so that the _id property is a number and not ObjectID(the default). If you do this, you would have to ensure the uniqueness of the _id value. Your query wouldn't need to change if you do this. You schema would then be something like this:
export const PlayerSchema = new mongoose.Schema({
_id: Number,
name: String,
score: Number,
createdAt: { type: Date, default: Date.now },
isDeleted: Boolean
});
If the is no hard requirement to have the _id field a number, you can use ObjectId values instead of Number, this would save you the stress of ensuring the uniqueness of the _id field. To do this, set the _id property as _id: mongoose.ObjectId
in the schema.
You also need to update the dto, model and every other place you have the player object typed to reflect the schema update i.e addition of "_id" property with a different type and maybe the removal of the former "id" property.
In case you are wondering how the _id field got there; it is a property of every MongoDB document, it serves as the primary key. Even if you do not add it in your schema, either the MongoDB driver(mongoose in this case) or the mongod server would add it for you. More details here