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
.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 ExampleTo 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.
- TodoItemEntity
- SubTaskEntity
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;}
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
- TodoItemDTO
- SubTaskDTO
import { FilterableField, IDField, KeySet, Connection } from '@nestjs-query/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, { disableRemove: 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;}
import { FilterableField, IDField, KeySet, Relation } from '@nestjs-query/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, { disableRemove: 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 ExampleIn this example, we'll add tags
to todoItems
by storing an array of tag
references on the todoItems
.
- TodoItemEntity
- TagEntity
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(); }}
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
- TodoItemDTO
- TagDTO
import { FilterableField, IDField, KeySet, Connection } from '@nestjs-query/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;}
import { FilterableField, IDField, KeySet, Connection } from '@nestjs-query/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, { disableUpdate: true, disableRemove: true })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;}