AgentSkillsCN

mongoose

NestJS 中的 Mongoose 模式,包括实体定义、文档/模型接口、查询、嵌入式模式以及辅助工具。当您需要:(1) 使用 @Schema/@Prop 装饰器创建 Mongoose 实体;(2) 为类型安全定义 Document 和 Model 接口;(3) 使用 FilterQuery 与聚合管道编写查询;(4) 处理嵌入式子文档与 DocumentArray;(5) 实现自定义 setter/getter/virtuals;(6) 为模式属性添加验证时,可使用此技能。

SKILL.md
--- frontmatter
name: mongoose
description: Mongoose patterns for NestJS including entity definitions, document/model interfaces, queries, embedded schemas, and helpers. Use when (1) creating Mongoose entities with @Schema/@Prop decorators, (2) defining Document and Model interfaces for type safety, (3) writing queries with FilterQuery and aggregation pipelines, (4) working with embedded subdocuments and DocumentArrays, (5) implementing custom setters/getters/virtuals, (6) adding validation to schema properties.

Mongoose Patterns

Quick Reference

This skill provides comprehensive Mongoose patterns for NestJS applications. Load reference files as needed:

  • entities.md - @Schema/@Prop decorators, SchemaFactory, indexes, Mongoose 9 id virtual
  • documents.md - HydratedDocument, Model types, @InjectModel pattern, DocumentArray typing
  • queries.md - find/findOne, FilterQuery, operators ($in, $or, $elemMatch), aggregation pipelines
  • embedded-schemas.md - Subdocument entities, embedding patterns, DocumentArray manipulation
  • helpers.md - Custom setters (parseNumber, parseDate), getters, virtuals, validation

Core Entity Structure

typescript
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';

import { Types } from 'mongoose';

@Schema({
  timestamps: true,
  versionKey: false,
  toJSON: { virtuals: true },
  toObject: { virtuals: true },
})
export class CarType {
  @Prop({ required: true, unique: true })
  name: string;

  @Prop({ type: Number, unique: true, sparse: true })
  rshopId?: number;

  @Prop({ type: Boolean, default: true })
  new?: boolean;

  createdAt: Date;
  updatedAt?: Date;
}

export const CarTypeSchema = SchemaFactory.createForClass(CarType);

// Add id virtual (Mongoose 9 no longer provides this by default)
CarTypeSchema.virtual('id').get(function (this: CarType & { _id: Types.ObjectId }) {
  return this._id.toHexString();
});

Import Organization

Follow this strict order:

  1. Framework imports (@nestjs/mongoose, @nestjs/common)
  2. Third-party packages (mongoose, date-fns)
  3. Generated files (src/generated/...)
  4. Helper utilities (src/database/...)
  5. Common modules (src/common/...)
  6. Application modules (src/modules/...)
  7. Relative imports (./, ../)

Document and Model Interfaces

typescript
// car-document.interface.ts
import { HydratedDocument, Types } from 'mongoose';

import { Car } from '../entities/car.entity';
import { CarEvent } from '../entities/car-event.entity';

export interface CarDocumentOverrides {
  id: string;
  history: Types.DocumentArray<CarEvent>;
}

export interface CarDocument
  extends HydratedDocument<Car, CarDocumentOverrides> {}

// car-model.interface.ts
import { Model } from 'mongoose';

export type CarModel = Model<Car, unknown, unknown, unknown, CarDocument>;

Service with Model Injection

typescript
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';

import { Car } from './entities/car.entity';
import { CarDocument } from './interfaces/car-document.interface';
import { CarModel } from './interfaces/car-model.interface';

@Injectable()
export class CarsService {
  constructor(
    @InjectModel(Car.name) private carModel: CarModel,
  ) {}

  // CRUD methods
  findAll(): Promise<CarDocument[]> {
    return this.carModel.find().exec();
  }

  findOne(id: string): Promise<CarDocument | null> {
    return this.carModel.findById(id).exec();
  }

  create(data: CreateCarInput): Promise<CarDocument> {
    const car = new this.carModel(data);
    return car.save();
  }

  async update(car: CarDocument, data: UpdateCarInput): Promise<CarDocument> {
    car.set(data);
    return car.save();
  }

  async delete(car: CarDocument): Promise<CarDocument> {
    await car.deleteOne();
    return car;
  }
}

When to Load Reference Files

Defining entities?

Setting up type safety?

Writing queries?

Working with nested data?

Custom data transformation?