Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

651
Views
How to check reference when inserting in MongoDB (typegraphql, typegoose)?

Let say I have a simple collection events created by TypeGraphql and Typegoose which stores objects like:

{ _id: ObjectId(...), name: 'SomeEvent', category: ObjectId('...') }

and corresponding type:

@ObjectType()
export class Event {
  @Field(() => ID)
  _id!: Types.ObjectId

  @prop({ ref: 'Category' })
  @Field(() => Category)
  category!: Ref<Category>

  @prop()
  @Field()
  name!: string
}

I have also collection categories which contains right now only _id and name.

Now I want to insert some Event to database. Is it possible to automatically check if categoryId provided in input exist in collection categories and if it does not, throw an error? Right now, event can be added with anything in category field and next when I try to get it by query it throws an error that category cannot be resolved because there is no category with this ID. I know, that I can check it manually during adding event but if I have more fields like that it will be problematic.

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

With the help of Martin Devillers answer I was able to write a validator to validate referenced documents using class-validator with typegoose.

This is my refdoc.validator.ts:

import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from "class-validator";
import { Injectable } from "@nestjs/common";
import { getModelForClass } from "@typegoose/typegoose";


@ValidatorConstraint({ name: "RefDoc", async: true })
@Injectable()
export class RefDocValidator implements ValidatorConstraintInterface {

    async validate(refId: string, args: ValidationArguments) {
        const modelClass = args.constraints[0];
        return getModelForClass(modelClass).exists({ _id: refId })
    }

    defaultMessage(): string {
        return "Referenced Document not found!";
    }
}

Then I can apply it on the DTO or model with the @Validate-Decorator. The Argument I'm passing in is the typegoose model.

@Validate(RefDocValidator, [Costcenter])
costcenterId: string;

Seems to be working for me, I'm open for any improvements..

Edit: Even better with custom decorator, as Martin Devillers suggested:

refdoc.validator.ts

import { registerDecorator, ValidationArguments, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface } from "class-validator";
import { Injectable } from "@nestjs/common";
import { getModelForClass } from "@typegoose/typegoose";


@ValidatorConstraint({ name: "RefDoc", async: true })
@Injectable()
export class RefDocValidator implements ValidatorConstraintInterface {

    async validate(refId: string, args: ValidationArguments) {
        const modelClass = args.constraints[0];
        return getModelForClass(modelClass).exists({ _id: refId })
    }

    defaultMessage(): string {
        return "Referenced Document not found!";
    }
}

export function RefDocExists(modelClass: any, validationOptions?: ValidationOptions) {
    return function (object: Object, propertyName: string) {
        registerDecorator({
            name: 'RefDocExists',
            target: object.constructor,
            propertyName: propertyName,
            constraints: [modelClass],
            options: validationOptions,
            validator: RefDocValidator,
        });
    };
}

Then you can use it on the DTO like:

@ApiProperty()
@IsNotEmpty()
//@Validate(RefDocValidator, [Costcenter]) old
@RefDocExists(Costcenter) //new
costcenterId: string;
over 4 years ago · Santiago Trujillo Report

0

Out of the box, neither MongoDB nor mongoose nor typegoose offer any automated referential integrity checks.

At the database level, this feature doesn't exist (which is also one of the fundamental differences between a database like MongoDB and SQL Server/Oracle).

However, at the application level, you can achieve this behavior in various ways:

  1. Middleware. Mongoose middleware allows you add generalized behavior to your models. This is useful if you're inserting documents in your EventModel in various places in your codebase and don't want to repeat your validation logic. For example:
EventModel.path('category').validate(async (value, respond) => {
    const categoryExists = await CategoryModel.exists({ _id: value })
    respond(categoryExists)
})
  1. Mongoose plugins. A plugin like mongoose-id-validator allows you to add the above behavior to any type of document reference in all your schemas.
  2. Manually. Probably the least favorite option, but I'm mentioning it for completeness sake: with mongoose's Model.exists() you can achieve this with a one-liner like: const categoryExists = await CategoryModel.exists({ _id: event.category })

To reiterate: all the above options are stopgaps. It's always possible for someone to go directly in your database and break referential integrity anyway.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!