In my NestJS app, in one of my Mongoose schemas I have embedded discriminators in an array. When iterating over the array and trying to access fields specific to one discriminator, for some reason this field is undefined.
Here for reference the NestJS docs on how to handle discriminators.
Schema definitions
User
@Schema()
export class User {
@Prop({ required: true, type: [BaseAction] })
subscriptionHistory: BaseAction[];
}
export type UserDocument = HydratedDocument<User>;
export const UserSchema = SchemaFactory.createForClass(User);
export type UserModel = Model<UserDocument>;
BaseAction and discriminators
@Schema({ _id: false, discriminatorKey: 'action', autoCreate: false })
export class BaseAction {
@Prop({ required: true, type: String, enum: SubscriptionAction })
action: string;
@Prop({ default: Date.now })
timestamp: Date;
}
export const BaseActionSchema = SchemaFactory.createForClass(BaseAction);
@Schema({ _id: false })
export class UpgradeAction {
action: string = SubscriptionAction.Upgrade;
timestamp: Date;
@Prop({ required: true, type: Object })
details: SubscriptionChange & StartDateChange & EndDateChange;
}
export const UpgradeActionSchema = SchemaFactory.createForClass(UpgradeAction);
/*
* Here exemplary the SubscriptionChange helper used in the 'details' prop
*/
@Schema({ _id: false })
class SubscriptionChange {
@Prop({ required: true })
oldVersion: number;
/* Some more properties */
}
Module
@Module({
imports: [
MongooseModule.forFeature([
{ name: User.name, schema: UserSchema },
{
name: BaseAction.name,
schema: UserSchema.path('subscriptionHistory').schema,
discriminators: [
{ name: SubscriptionAction.Upgrade, schema: UpgradeActionSchema },
/* further discriminators here */
],
},
])
],
/* controllers, providers, exports */
})
export class UserModule {}
The issue
In one of my services, I retrieve the user from the database and iterate over the subscriptionHistory array. I check for the action type and then want to read the details
property of the action.
When running in debug, I can see that the details field is in memory, but whenever I access it, it is undefined.
export class SomeService {
async someHandler(userId) {
const user = await this.userService.getUserById(userId); // works fine
const action = user.subscriptionHistory.find((h) => {
if (h.action === SubscriptionAction.Upgrade) { // works fine
console.log(h) // <-- 'details' is being printed
const { details } = h as UpgradeAction // I have to cast to be able to extract details
return details.oldVersion > 1; // This throws
}
});
}
}
The error being thrown is:
Cannot read properties of undefined (reading ‘oldVersion’)
In the debugger, I can see that h
is of type EmbeddedDocument
and that details
is there, but not accessible.
I believe, the issue has something to do with me not type casting correctly. Unfortunately, I don’t know how to solve this. How can I access details
?