> ## Documentation Index
> Fetch the complete documentation index at: https://www.nestjs-query.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Relations

Relations work a little differently in `typegoose` when compared to other relational ORMs such as `sequelize` or
`typeorm`. You can read more about relations (references) in `typegoose` \[here]\([https://mongoosejs.com/docs/populate](https://mongoosejs.com/docs/populate)
.html)

> [!NOTE]
>
> There are multiple ways to set of references in Typegoose. These are intended as a starting point.

> [!WARNING]
>
> Filtering on references is not supported by Typegoose.

## One to Many/Many To One Example

To set up a one to many/many to one relationship in Typegoose, you will store a reference in your document.

For example, lets add sub tasks to our todo items by storing a `todoItem` ref on our `subTask` and an array of sub-tasks on our `todoItem` entity.

> [tab] Todo Item
>
> ```ts title="todo-item/todo-item.entity.ts" {24-25} theme={null}
> import { Prop, modelOptions } from '@typegoose/typegoose'
> import { Base } from '@typegoose/typegoose/lib/defaultClasses'
>
> @modelOptions({ schemaOptions: { timestamps: true } })
> export class TodoItemEntity extends Base {
>
>   @Prop({ required: true })
>   title!: string
>
>   @Prop()
>   description?: string
>
>   @Prop({ required: true })
>   completed!: boolean
>
>   @Prop({ default: Date.now })
>   createdAt!: Date
>
>   @Prop({ default: Date.now })
>   updatedAt!: Date
>
>   @Prop({ default: 0 })
>   priority!: number
>
>   @Prop({ ref: () => SubTaskEntity })
>   subTasks: Ref<SubTaskEntity>[]
>
>   @Prop()
>   createdBy?: string
>
>   @Prop()
>   updatedBy?: string
> }
> ```

> [tab] Subtask
>
> ```ts title="sub-task/sub-task.entity.ts" {15-16} theme={null}
> import { Prop, modelOptions, Ref } from '@typegoose/typegoose'
> import { Base } from '@typegoose/typegoose/lib/defaultClasses'
>
> @modelOptions({ schemaOptions: { timestamps: true } })
> export class SubTaskEntity extends Base {
>
>   @Prop({ required: true })
>   title!: string
>
>   @Prop()
>   description?: string
>
>   @Prop({ required: true })
>   completed!: boolean
>
>   @Prop({ ref: () => TodoItemEntity, required: true })
>   todoItem!: Ref<TodoItemEntity>
>
>   @Prop()
>   createdAt!: Date
>
>   @Prop()
>   updatedAt!: Date
>
>   @Prop()
>   createdBy?: string
>
>   @Prop()
>   updatedBy?: string
> }
> ```

Now that we have the relationships defined, we can add the `@Relation` and `@Connection` to our DTOs

> [tab] Todo Item
>
> ```ts title="todo-item/todo-item.dto.ts" theme={null}
> import { FilterableField, IDField, KeySet, Connection } from '@ptc-org/nestjs-query-graphql'
> import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql'
> import { SubTaskDTO } from '../../sub-task/dto/sub-task.dto'
>
> @ObjectType('TodoItem')
> @KeySet(['id'])
> // disable the remove because mongoose does not support removing a virtual
>
> @Connection('subTasks', () => SubTaskDTO, { update: { enabled: true } })
> export class TodoItemDTO {
>
>   @IDField(() => ID)
>   id!: string
>
>   @FilterableField()
>   title!: string
>
>   @FilterableField({ nullable: true })
>   description?: string
>
>   @FilterableField()
>   completed!: boolean
>
>   @FilterableField(() => GraphQLISODateTime)
>   createdAt!: Date
>
>   @FilterableField(() => GraphQLISODateTime)
>   updatedAt!: Date
>
>   @Field()
>   age!: number
>
>   @FilterableField()
>   priority!: number
>
>   @FilterableField({ nullable: true })
>   createdBy?: string
>
>   @FilterableField({ nullable: true })
>   updatedBy?: string
> }
> ```

> [tab] Subtask
>
> ```ts title="sub-task/sub-task.dto.ts" theme={null}
> import { FilterableField, IDField, KeySet, Relation } from '@ptc-org/nestjs-query-graphql'
> import { ObjectType, ID, GraphQLISODateTime } from '@nestjs/graphql'
> import { TodoItemDTO } from '../../todo-item/dto/todo-item.dto'
>
> @ObjectType('SubTask')
> @KeySet(['id'])
> // disable the remove because a sub task cannot exist without a todoitem
>
> @Relation('todoItem', () => TodoItemDTO, { update: { enabled: true } })
> export class SubTaskDTO {
>
>   @IDField(() => ID)
>   id!: string
>
>   @FilterableField()
>   title!: string
>
>   @FilterableField({ nullable: true })
>   description?: string
>
>   @FilterableField()
>   completed!: boolean
>
>   @FilterableField(() => GraphQLISODateTime)
>   createdAt!: Date
>
>   @FilterableField(() => GraphQLISODateTime)
>   updatedAt!: Date
>
>   @FilterableField({ nullable: true })
>   createdBy?: string
>
>   @FilterableField({ nullable: true })
>   updatedBy?: string
> }
> ```

## Many To Many Example

In this example, we'll add `tags` to `todoItems` by storing an array of `tag` references on the `todoItems`.

> [tab] Todo Item
>
> ```ts title="todo-item/todo-item.entity.ts" {21-23} theme={null}
> import { Prop, modelOption, Ref } from '@typegoose/typegoose'
> import { Base } from '@typegoose/typegoose/lib/defaultClasses'
>
> @modelOptions({ schemaOptions: { timestamps: true } })
> export class TodoItemEntity extends Base {
>
>   @Prop({ required: true })
>   title!: string
>
>   @Prop()
>   description?: string
>
>   @Prop({ required: true })
>   completed!: boolean
>
>   @Prop({ default: Date.now })
>   createdAt!: Date
>
>   @Prop({ default: Date.now })
>   updatedAt!: Date
>
>   @Prop({ ref: () => TagEntity })
>   tags!: Ref<TagEntity>[]
>
>   @Prop({ default: 0 })
>   priority!: number
>
>   @Prop()
>   createdBy?: string
>
>   @Prop()
>   updatedBy?: string
>
>   public get id(): string {
>     // eslint-disable-next-line no-underscore-dangle
>     return this._id.toHexString()
>   }
> }
> ```

> [tab] Tag
>
> ```ts title="tag/tag.entity.ts" {33-38} theme={null}
> import { Base } from '@typegoose/typegoose/lib/defaultClasses'
> import { Prop, modelOptions, Ref } from '@typegoose/typegoose'
> import { Types } from 'mongoose'
> import { TodoItemEntity } from '../todo-item/todo-item.entity'
>
> @modelOptions({
>   schemaOptions: {
>     timestamps: true,
>     collection: 'tags',
>     toObject: { virtuals: true }
>   }
> })
> export class TagEntity implements Base {
>
>   _id!: Types.ObjectId
>
>   id!: string
>
>   @Prop({ required: true })
>   name!: string
>
>   @Prop()
>   createdAt!: Date
>
>   @Prop()
>   updatedAt!: Date
>
>   @Prop()
>   createdBy?: string
>
>   @Prop()
>   updatedBy?: string
>
>   @Prop({
>     ref: 'TodoItemEntity',
>     localField: '_id',
>     foreignField: 'tags'
>   })
>   todoItems?: Ref<TodoItemEntity>[]
> }
> ```

Now that we have the relationship defined, we can add the `@Connection` to our DTOS

> [tab] Todo Item
>
> ```ts title="todo-item/todo-item.dto.ts" theme={null}
> import { FilterableField, IDField, KeySet, Connection } from '@ptc-org/nestjs-query-graphql'
> import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql'
> import { TagDTO } from '../../tag/dto/tag.dto'
>
> @ObjectType('TodoItem')
> @KeySet(['id'])
> @Connection('tags', () => TagDTO)
> export class TodoItemDTO {
>
>   @IDField(() => ID)
>   id!: string
>
>   @FilterableField()
>   title!: string
>
>   @FilterableField({ nullable: true })
>   description?: string
>
>   @FilterableField()
>   completed!: boolean
>
>   @FilterableField(() => GraphQLISODateTime)
>   createdAt!: Date
>
>   @FilterableField(() => GraphQLISODateTime)
>   updatedAt!: Date
>
>   @Field()
>   age!: number
>
>   @FilterableField()
>   priority!: number
>
>   @FilterableField({ nullable: true })
>   createdBy?: string
>
>   @FilterableField({ nullable: true })
>   updatedBy?: string
> }
> ```

> [tab] Tag
>
> ```ts title="tag/tag.dto.ts" theme={null}
> import { FilterableField, IDField, KeySet, Connection } from '@ptc-org/nestjs-query-graphql'
> import { ObjectType, ID, GraphQLISODateTime } from '@nestjs/graphql'
> import { TodoItemDTO } from '../../todo-item/dto/todo-item.dto'
>
> @ObjectType('Tag')
> @KeySet(['id'])
> // disable update and remove since it is a virtual in the entity
>
> @Connection('todoItems', () => TodoItemDTO)
> export class TagDTO {
>
>   @IDField(() => ID)
>   id!: string
>
>   @FilterableField()
>   name!: string
>
>   @FilterableField(() => GraphQLISODateTime)
>   createdAt!: Date
>
>   @FilterableField(() => GraphQLISODateTime)
>   updatedAt!: Date
>
>   @FilterableField({ nullable: true })
>   createdBy?: string
>
>   @FilterableField({ nullable: true })
>   updatedBy?: string
> }
> ```

## Discriminators

Typegoose supports mongoose [discriminators](https://mongoosejs.com/docs/discriminators.html). `nestjs-query` provides support for them through the `NestjsQueryTypegooseModule`.

To use discriminators you need to define them in your `NestjsQueryTypegooseModule.forFeature` call.

When working with discriminators, `nestjs-query` requires you to provide a service class for each discriminated entity. This is necessary for the auto-generated resolvers to be created correctly. These service classes are also the perfect place to add any custom business logic for your discriminated entities.

```ts title="todo-item/todo-item.module.ts" theme={null}
import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql'
import { NestjsQueryTypegooseModule, TypegooseQueryService } from '@ptc-org/nestjs-query-typegoose'
import { Module } from '@nestjs/common'
import { TodoItemEntity } from './entities/todo-item.entity'
import { TodoTaskEntity } from './entities/todo-task.entity'
import { TodoAppointmentEntity } from './entities/todo-appointment.entity'
import { TodoItemDTO } from './dto/todo-item.dto'
import { TodoTaskDTO } from './dto/todo-task.dto'
import { TodoAppointmentDTO } from './dto/todo-appointment.dto'
import { CreateTodoTaskInput } from './dto/create-todo-task.input'
import { CreateTodoAppointmentInput } from './dto/create-todo-appointment.input'
import { InjectModel } from '@m8a/nestjs-typegoose'
import { ReturnModelType } from '@typegoose/typegoose'

const typegooseModule = NestjsQueryTypegooseModule.forFeature([
  {
    typegooseClass: TodoItemEntity,
    discriminators: [{ typegooseClass: TodoTaskEntity }, { typegooseClass: TodoAppointmentEntity }]
  }
])

class TodoTaskEntityService extends TypegooseQueryService<TodoTaskEntity> {

  constructor(@InjectModel(TodoTaskEntity) readonly model: ReturnModelType<typeof TodoTaskEntity>) {
    super(model)
  }
}

class TodoAppointmentService extends TypegooseQueryService<TodoAppointmentEntity> {

  constructor(@InjectModel(TodoAppointmentEntity) readonly model: ReturnModelType<typeof TodoAppointmentEntity>) {
    super(model)
  }
}

@Module({
  imports: [
    NestjsQueryGraphQLModule.forFeature({
      imports: [typegooseModule],
      resolvers: [
        {
          DTOClass: TodoItemDTO,
          EntityClass: TodoItemEntity,
          create: { disabled: true }, // Disable create for the base entity
          update: { disabled: true } // Disable update for the base entity
        },
        {
          DTOClass: TodoTaskDTO,
          EntityClass: TodoTaskEntity,
          // Tell the resolver to use our custom input for the create operation
          CreateDTOClass: CreateTodoTaskInput,
          ServiceClass: TodoTaskEntityService
        },
        {
          DTOClass: TodoAppointmentDTO,
          EntityClass: TodoAppointmentEntity,
          // Tell the resolver to use our custom input for the create operation
          CreateDTOClass: CreateTodoAppointmentInput,
          ServiceClass: TodoAppointmentService
        }
      ],
      services: [TodoTaskEntityService, TodoAppointmentService]
    })
  ]
})
export class TodoItemModule {}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.