NestJS module that provides seamless integration between NestJS and Mongoose ODM for MongoDB database operations
80
Pending
Does it follow best practices?
Impact
80%
1.02xAverage score across 10 eval scenarios
Pending
The risk profile of this skill
Pre-built pipes for validating and parsing MongoDB ObjectIds in request parameters and body data. These pipes integrate with NestJS's validation system to ensure data integrity when working with MongoDB documents.
Validates if a string is a valid MongoDB ObjectId format without converting it to an ObjectId instance.
class IsObjectIdPipe implements PipeTransform {
/**
* Validates that a string is a valid MongoDB ObjectId format
* @param value - String value to validate
* @returns The original string if valid
* @throws BadRequestException if invalid ObjectId format
*/
transform(value: string): string;
}Usage Examples:
import { Controller, Get, Param } from '@nestjs/common';
import { IsObjectIdPipe } from '@nestjs/mongoose';
@Controller('users')
export class UsersController {
// Validate ObjectId in route parameter
@Get(':id')
async findOne(@Param('id', IsObjectIdPipe) id: string) {
// id is guaranteed to be a valid ObjectId string
return this.usersService.findById(id);
}
// Multiple ObjectId parameters
@Get(':userId/posts/:postId')
async findUserPost(
@Param('userId', IsObjectIdPipe) userId: string,
@Param('postId', IsObjectIdPipe) postId: string,
) {
return this.postsService.findByUserAndId(userId, postId);
}
// Optional ObjectId validation
@Get()
async findAll(@Query('authorId', new IsObjectIdPipe({ optional: true })) authorId?: string) {
if (authorId) {
return this.usersService.findByAuthor(authorId);
}
return this.usersService.findAll();
}
}
// In request body validation
import { Body, Post } from '@nestjs/common';
@Controller('comments')
export class CommentsController {
@Post()
async create(@Body() createCommentDto: CreateCommentDto) {
return this.commentsService.create(createCommentDto);
}
}
// DTO with ObjectId validation
export class CreateCommentDto {
@IsString()
content: string;
@Transform(({ value }) => value, { toClassOnly: true })
@Validate(IsObjectIdPipe)
postId: string;
@Transform(({ value }) => value, { toClassOnly: true })
@Validate(IsObjectIdPipe)
authorId: string;
}Validates and converts a string to a MongoDB ObjectId instance for direct use with Mongoose operations.
class ParseObjectIdPipe implements PipeTransform {
/**
* Validates and converts a string to MongoDB ObjectId
* @param value - String value to parse
* @returns ObjectId instance
* @throws BadRequestException if invalid ObjectId format
*/
transform(value: string): Types.ObjectId;
}Usage Examples:
import { Controller, Get, Param, Delete } from '@nestjs/common';
import { ParseObjectIdPipe } from '@nestjs/mongoose';
import { Types } from 'mongoose';
@Controller('users')
export class UsersController {
// Parse ObjectId in route parameter
@Get(':id')
async findOne(@Param('id', ParseObjectIdPipe) id: Types.ObjectId) {
// id is now a proper ObjectId instance
return this.usersService.findById(id);
}
@Delete(':id')
async remove(@Param('id', ParseObjectIdPipe) id: Types.ObjectId) {
return this.usersService.remove(id);
}
// Complex route with multiple ObjectIds
@Get(':userId/orders/:orderId/items/:itemId')
async findOrderItem(
@Param('userId', ParseObjectIdPipe) userId: Types.ObjectId,
@Param('orderId', ParseObjectIdPipe) orderId: Types.ObjectId,
@Param('itemId', ParseObjectIdPipe) itemId: Types.ObjectId,
) {
return this.ordersService.findItemByIds(userId, orderId, itemId);
}
}
// Service usage with parsed ObjectIds
@Injectable()
export class UsersService {
constructor(@InjectModel(User.name) private userModel: Model<User>) {}
async findById(id: Types.ObjectId): Promise<User> {
// Can use ObjectId directly in Mongoose operations
return this.userModel.findById(id).exec();
}
async findByIds(ids: Types.ObjectId[]): Promise<User[]> {
return this.userModel.find({ _id: { $in: ids } }).exec();
}
async updateRelationship(userId: Types.ObjectId, friendId: Types.ObjectId): Promise<User> {
return this.userModel.findByIdAndUpdate(
userId,
{ $addToSet: { friends: friendId } },
{ new: true }
).exec();
}
}import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
import { isValidObjectId, Types } from 'mongoose';
@Injectable()
export class CustomObjectIdPipe implements PipeTransform {
constructor(private readonly options: { optional?: boolean; allowNull?: boolean } = {}) {}
transform(value: any, metadata: ArgumentMetadata): string | Types.ObjectId | null {
// Handle optional values
if (this.options.optional && (value === undefined || value === '')) {
return undefined;
}
// Handle null values
if (this.options.allowNull && value === null) {
return null;
}
// Validate ObjectId format
if (!isValidObjectId(value)) {
throw new BadRequestException(`Invalid ObjectId format: ${value}`);
}
// Return as string or ObjectId based on needs
return metadata.metatype === Types.ObjectId ? new Types.ObjectId(value) : value;
}
}
// Usage with custom options
@Controller('posts')
export class PostsController {
@Get()
async findAll(
@Query('categoryId', new CustomObjectIdPipe({ optional: true })) categoryId?: string,
@Query('authorId', new CustomObjectIdPipe({ optional: true })) authorId?: string,
) {
const filters: any = {};
if (categoryId) filters.category = categoryId;
if (authorId) filters.author = authorId;
return this.postsService.findWithFilters(filters);
}
}@Injectable()
export class ParseObjectIdArrayPipe implements PipeTransform {
transform(value: string | string[]): Types.ObjectId[] {
const ids = Array.isArray(value) ? value : [value];
return ids.map(id => {
if (!isValidObjectId(id)) {
throw new BadRequestException(`Invalid ObjectId format: ${id}`);
}
return new Types.ObjectId(id);
});
}
}
@Controller('users')
export class UsersController {
@Post('bulk-update')
async bulkUpdate(
@Body('userIds', ParseObjectIdArrayPipe) userIds: Types.ObjectId[],
@Body() updateData: any,
) {
return this.usersService.bulkUpdate(userIds, updateData);
}
@Delete('bulk-delete')
async bulkDelete(@Body('ids', ParseObjectIdArrayPipe) ids: Types.ObjectId[]) {
return this.usersService.bulkDelete(ids);
}
}import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Global validation pipe with ObjectId support
app.useGlobalPipes(
new ValidationPipe({
transform: true,
whitelist: true,
forbidNonWhitelisted: true,
}),
);
await app.listen(3000);
}
bootstrap();
// Custom global ObjectId validation
@Injectable()
export class GlobalObjectIdValidationPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
// Auto-detect ObjectId strings in parameters
if (metadata.type === 'param' && typeof value === 'string' && isValidObjectId(value)) {
return new Types.ObjectId(value);
}
return value;
}
}
// Register globally
app.useGlobalPipes(new GlobalObjectIdValidationPipe());import { IsString, IsOptional, ValidateNested, Type, registerDecorator, ValidationOptions } from 'class-validator';
import { Transform } from 'class-transformer';
import { isValidObjectId, Types } from 'mongoose';
// Custom ObjectId validator
export function IsObjectId(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'isObjectId',
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate(value: any) {
return typeof value === 'string' && isValidObjectId(value);
},
defaultMessage() {
return '$property must be a valid ObjectId';
},
},
});
};
}
// DTO with ObjectId validation
export class CreatePostDto {
@IsString()
title: string;
@IsString()
content: string;
@IsObjectId()
@Transform(({ value }) => value.toString())
authorId: string;
@IsOptional()
@IsObjectId()
@Transform(({ value }) => value ? value.toString() : undefined)
categoryId?: string;
@IsOptional()
@IsObjectId({ each: true })
@Transform(({ value }) => Array.isArray(value) ? value.map(id => id.toString()) : [])
tagIds?: string[];
}
@Controller('posts')
export class PostsController {
@Post()
async create(@Body() createPostDto: CreatePostDto) {
// All ObjectIds are validated by class-validator
return this.postsService.create(createPostDto);
}
}The validation pipes throw standard NestJS BadRequestException when validation fails:
// Example error responses
{
"statusCode": 400,
"message": "Validation failed (ObjectId is expected)",
"error": "Bad Request"
}
// Custom error handling
@Injectable()
export class CustomObjectIdPipe implements PipeTransform {
transform(value: string): Types.ObjectId {
if (!isValidObjectId(value)) {
throw new BadRequestException({
statusCode: 400,
message: `Invalid ObjectId format: "${value}". ObjectId must be a 24 character hex string.`,
error: 'Invalid ObjectId',
provided: value,
});
}
return new Types.ObjectId(value);
}
}docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10