Home > Software design >  Typegoose/ Mongoose nested discriminator is not accepting array
Typegoose/ Mongoose nested discriminator is not accepting array

Time:12-28

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 with String, 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 the Mixed type, in this case String would be appropiate
  • default: new Date() is likely not what you want, you probably want to change it to default: () => new Date(), the way it is currently defined evaluates default: 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 and WorkflowTaskType)

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

  • Related