Mongodb Typegoose is throwing error "Tried to set nested object field `field` to array ``" for nested discriminator field

321 views Asked by At

I am building a web application using MongoDB and NodeJS (Typescript). I am using Typegoose for interacting with mongodb from my application. Now, I am having a problem using nested discriminator especially inserting array of object to the field. Below is my code.

These are my model classes

import {
  getModelForClass,
  modelOptions,
  prop,
  Ref
} from '@typegoose/typegoose';
import {Schema, Types} from "mongoose";
import { Page, SubPage } from './page';

export enum AlertMessageType {
  primary = 'primary',
  info = 'info',
  danger = 'danger',
  warning = 'warning'
}

export enum ContentType {
  htmlBlock = 'html-block',
  header = 'header',
  codeBlock = 'code-block',
  alertMessage = 'alert-message'
}

@modelOptions({
  schemaOptions: {
    discriminatorKey: 'type',
    _id: false,
    id: false
  }
})
export class PageSectionContent {
  @prop({ required: true, type: Schema.Types.ObjectId })
  public _id!: Types.ObjectId;

  @prop({ type: Schema.Types.String, required: true })
  public type!: ContentType;

  @prop({ type: Schema.Types.Boolean, required: true, default: true })
  public isActive!: boolean;
}

export class AlertMessageContent extends PageSectionContent {
  @prop({ type: String, required: false })
  public iconPath?: string;

  @prop({ type: String, required: true })
  public alertType!: AlertMessageType;

  @prop({ type: String, required: false })
  public title?: string;

  @prop({ type: String, required: true })
  public message!: string;
}

export class HtmlBlockContent extends PageSectionContent {
  @prop({ type: String, required: false })
  public title?: string;

  @prop({ required: true, type: String })
  public content!: string;
}

export class CodeBlockContent extends PageSectionContent {
  @prop({ required: true, type: String })
  public code!: string;
}

export class HeaderContent extends PageSectionContent {
  @prop({ type: String, required: true })
  public title?: string;
}

export class PageSection {
  @prop({ required: true, type: String })
  public title!: string;

  @prop({ required: true, ref: () => Page })
  public page!: Ref<Page>;
  
  @prop({ required: false, ref: () => SubPage })
  public subPage?: Ref<SubPage>;

  @prop({
    required: true,
    type: PageSectionContent,
    discriminators: () => [
      {
        type: HtmlBlockContent,
        value: ContentType.htmlBlock
      },
      {
        type: HeaderContent,
        value: ContentType.header
      },
      {
        type: CodeBlockContent,
        value: ContentType.codeBlock
      },
      {
        type: AlertMessageContent,
        value: ContentType.alertMessage
      }
    ],
    default: [],
  })
  public contents!: PageSectionContent[];

  @prop({ type: Boolean, required: true, default: true })
  public isActive!: boolean;
}

export const PageSectionModel = getModelForClass(PageSection);

As you can see in the code, PageSection class has a discriminators (array) field called contents.

The I tried to create a PageSection document using the following data.

{
      title: 'Eaque magnam illo consequatur laboriosam vel natus minima deserunt.',
      contents: [
        {
          _id: new ObjectId("6434984567b1da87aab5f10d"),
          type: 'header',
          title: 'Aliquid asperiores incidunt eligendi.',
          isActive: false
        }
      ],
      isActive: false,
      page: new ObjectId("6434984567b1da87aab5f106")
    }

This is the code

await PageSectionModel.create({
      title: section.title,
      isActive: section.isActive,
      page: page.id,
      contents: contentsToInsert
    });

I am getting the following error.

'PageSection validation failed: contents: Tried to set nested object field `contents` to array ``'

But instead of passing array to the contents field, when I pass a single object like this, it is not throwing error.

{
              _id: new ObjectId("6434984567b1da87aab5f10d"),
              type: 'header',
              title: 'Aliquid asperiores incidunt eligendi.',
              isActive: false
            }

But I need to pass the array.

I also tried declaring the discriminator field like this

@prop({
    required: true,
    type: () => [PageSectionContent],
    discriminators: () => [
      {
        type: HtmlBlockContent,
        value: ContentType.htmlBlock
      },
      {
        type: HeaderContent,
        value: ContentType.header
      },
      {
        type: CodeBlockContent,
        value: ContentType.codeBlock
      },
      {
        type: AlertMessageContent,
        value: ContentType.alertMessage
      }
    ],
    default: [],
  })
  public contents!: PageSectionContent[];

It is still throwing the same error. What is wrong with my code and how can I fix it?

0

There are 0 answers