I am building a Node application using TypeScript and MongoDB as my application's database. I am using Typegoose to interact with MongoDB from Node JS application. Now, I am having a problem with using Nested Discriminator, https://typegoose.github.io/typegoose/docs/guides/advanced/nested-discriminators/ in my application.
I have a model called Workflow with the following code.
export class Workflow {
@prop({ required: true, type: Date, default: new Date() })
public createdAt!: Date;
@prop({ required: true, type: () => [WorkflowTask] })
public tasks!: WorkflowTask[];
}
export const WorkflowModel = getModelForClass(Workflow);
As you can see, a workflow can have many tasks (WorkflowTask). Below is the dummy code of my WorkflowTask model.
export class WorkflowTask {
@prop({ required: false, type: Schema.Types.String })
public title?: string;
@prop({ required: false, type: Schema.Types.String })
public description?: string;
@prop({ required: true, type: Schema.Types.String })
public type!: WorkflowTaskType;
@prop({
required: true,
type: FormContent,
discriminators: () => [
{
type: TextFormFieldContent,
value: FormWorkflowTaskContentType.TEXT_FORM_FIELD
},
{
type: NumberFormFieldContent,
value: FormWorkflowTaskContentType.NUMBER_FORM_FIELD
}
],
default: []
})
public formContents!: FormContent[];
}
As you can see, a WorkflowTask can have many FormContent where I put the discriminator in.
The following are some dummy code for my Workflow content classes.
export class FormContent {
@prop({ required: false, type: Schema.Types.String })
public label?: string;
@prop({ required: false, type: Schema.Types.String })
public message?: string;
@prop({ required: false, type: Schema.Types.String })
public description?: string;
@prop({ required: true, type: Schema.Types.String })
public type!: FormWorkflowTaskContentType;
}
export class TextFormFieldContent extends FormContent {
@prop({ required: false, type: Schema.Types.String })
public defaultValue?: string;
}
export class EmailFormFieldContent extends FormContent {
@prop({ required: false, type: Schema.Types.String })
public defaultValue?: string;
}
export class NumberFormFieldContent extends FormContent {
@prop({ required: false, type: Schema.Types.String })
public defaultValue?: string;
}
export class MultiSelectFieldContent extends FormContent {
@prop({ required: false, type: Schema.Types.Array, default: [] })
public defaultValue?: string[];
}
At the moment, I am only trying to create a workflow with empty tasks using the following code.
await WorkflowModel.create({
createdAt: new Date(),
tasks: []
});
I am getting the following error when I run the code.
ValidationError: Workflow validation failed: tasks: Cast to Embedded failed for value "[]" (type Array) at path "tasks" because of "ObjectExpectedError"
I am not even populating the tasks for the workflow. I followed the page correctly. What is wrong with my code and how can I fix it?
CodePudding user response:
Looking at the typegoose documentation for the type
option of the @prop
decorator it seems like the type
you pass should be the type of the array's items:
Example: Arrays (array item types can't be automatically inferred via Reflect)
class Dummy { @prop({ type: String }) public hello: string[]; }
If that's the case the decorator may be defined as:
@prop({ required: true, type: () => WorkflowTask })
public tasks!: WorkflowTask[];
or
@prop({ required: true, type: WorkflowTask })
public tasks!: WorkflowTask[];
CodePudding user response:
I dont see anything obviously wrong with your provided code, and i also locally tried to test your code which was working just fine.
Reproduction Repository / Branch: https://github.com/typegoose/typegoose-testing/tree/SO74916118
But there are some notes:
- you can improve readability by replacing
Schema.Types.String
withString
, typegoose & mongoose will automatically translate it to the proper Schema-Type type: Schema.Types.Array
is likely not what you want to set, this will effectively be of theMixed
type, in this caseString
would be appropiatedefault: new Date()
is likely not what you want, you probably want to change it todefault: () => new Date()
, the way it is currently defined evaluatesdefault: new Date()
at the time of loading the file once instead of everytime a document is created- some values were not provided and have been inferred in the reproduction code (not provided were
FormWorkflowTaskContentType
andWorkflowTaskType
)
PS: another answer has pointed out that type: () => [WorkflowTask]
is not supported, which is not true; the syntax of type: [Type]
is supported since typegoose 7.4.0
Slight Note: if you code fails, you may just be on old versions or you are running into Circular Dependencies