mongoose when compared to other relational ORMs such as sequelize or typescript. You can read more about relations (references) in mongoose here
There are multiple ways to set of references in
mongoose there are intended as starting point.Filtering on references is not supported by mongoose.
One to Many/Many To One Example
To set up a one to many/many to one relationship in mongoose you will store a reference in your document For example lets add sub tasks to our todo items by storing atodoItem ref on our subTask
- Todo Item
- Subtask
todo-item/todo-item.entity.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
import { SchemaTypes, Types, Document } from 'mongoose'
@Schema({ timestamps: true })
export class TodoItemEntity extends Document {
@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()
createdBy?: string
@Prop()
updatedBy?: string
}
export const TodoItemEntitySchema = SchemaFactory.createForClass(TodoItemEntity)
TodoItemEntitySchema.virtual('subTasks', {
ref: 'SubTaskEntity',
localField: '_id',
foreignField: 'todoItem'
})
sub-task/sub-task.entity.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
import { SchemaTypes, Types, Document } from 'mongoose'
@Schema({ timestamps: true })
export class SubTaskEntity extends Document {
@Prop({ required: true })
title!: string
@Prop()
description?: string
@Prop({ required: true })
completed!: boolean
@Prop({ type: SchemaTypes.ObjectId, ref: 'TodoItemEntity', required: true })
todoItem!: Types.ObjectId
@Prop()
createdAt!: Date
@Prop()
updatedAt!: Date
@Prop()
createdBy?: string
@Prop()
updatedBy?: string
}
export const SubTaskEntitySchema = SchemaFactory.createForClass(SubTaskEntity)
@Relation and @CursorConnection to our DTOs
- Todo Item
- Subtask
todo-item/todo-item.dto.ts
import { FilterableField, IDField, KeySet, CursorConnection } 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
@CursorConnection('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
}
sub-task/sub-task.dto.ts
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 addtags to todoItems by storing an array of tag references on the todoItems.
- Todo Item
- Tag
todo-item/todo-item.entity.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
import { SchemaTypes, Types, Document } from 'mongoose'
@Schema({ timestamps: true })
export class TodoItemEntity extends Document {
@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
// notice the brackets around the prop options
@Prop([{ type: SchemaTypes.ObjectId, ref: 'TagEntity' }])
tags!: Types.ObjectId[]
@Prop({ default: 0 })
priority!: number
@Prop()
createdBy?: string
@Prop()
updatedBy?: string
}
export const TodoItemEntitySchema = SchemaFactory.createForClass(TodoItemEntity)
tag/tag.entity.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
import { Document } from 'mongoose'
@Schema({ timestamps: true })
export class TagEntity extends Document {
@Prop({ required: true })
name!: string
@Prop()
createdAt!: Date
@Prop()
updatedAt!: Date
@Prop()
createdBy?: string
@Prop()
updatedBy?: string
}
export const TagEntitySchema = SchemaFactory.createForClass(TagEntity)
TagEntitySchema.virtual('todoItems', {
ref: 'TodoItemEntity',
localField: '_id',
foreignField: 'tags'
})
@CursorConnection to our DTOS
- Todo Item
- Tag
todo-item/todo-item.dto.ts
import { FilterableField, IDField, KeySet, CursorConnection } 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'])
@CursorConnection('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
}
tag/tag.dto.ts
import { FilterableField, IDField, KeySet, CursorConnection } 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
@CursorConnection('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
}