NestJS使用Mongoose定义数组类型Schema时出现栈溢出错误
问题:NestJS Mongoose Schema 数组类型属性导致栈溢出错误
我用NestJS为MongoDB构建数据Schema时,遇到了栈溢出错误,具体代码和错误信息如下:
相关代码
Cart Schema
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; import { ProductInCartDto } from "../dtos/product-in-cart.dto"; @Schema({ collection: 'carts', timestamps: true }) export class Cart { @Prop() userId: number; @Prop() products: ProductInCartDto[]; } export const CartSchema = SchemaFactory.createForClass(Cart);
ProductInCartDto
export class ProductInCartDto { storeId: number; productList: {[productId: number]: number}[]; }
测试用CartModel
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Cart } from '../domains/schemas/cart.schema'; import { Model } from 'mongoose'; @Injectable() export class CartModel { constructor(@InjectModel(Cart.name) private cartModel: Model<Cart>) {} async createCart() { return await this.cartModel.create({ userId: 1, products: [{ storeId: 1, productList: { 1: 1, 2: 2 } }] }); } }
错误信息
[Nest] 33570 - 06/24/2024, 9:14:36 PM ERROR [HttpExceptionFilter] Maximum call stack size exceeded RangeError: Maximum call stack size exceeded at MetadataStorage.getExposedProperties (/home/long/vegeta/HealthyFoodApplication_BackEnd/node_modules/src/MetadataStorage.ts:115:23) at TransformOperationExecutor.getKeys (/home/long/vegeta/HealthyFoodApplication_BackEnd/node_modules/src/TransformOperationExecutor.ts:461:54) at TransformOperationExecutor.transform (/home/long/vegeta/HealthyFoodApplication_BackEnd/node_modules/src/TransformOperationExecutor.ts:150:25) at TransformOperationExecutor.transform (/home/long/vegeta/HealthyFoodApplication_BackEnd/node_modules/src/TransformOperationExecutor.ts:327:31) at TransformOperationExecutor.transform (/home/long/vegeta/HealthyFoodApplication_BackEnd/node_modules/src/TransformOperationExecutor.ts:32
注:数据能成功存入MongoDB,但只要Schema包含数组类型属性就会触发该错误,移除数组则报错消失。
错误原因
核心问题是你直接在Mongoose Schema的@Prop()中使用了**DTO类(ProductInCartDto)**作为数组元素类型。NestJS的Mongoose模块结合class-transformer处理Schema元数据时,会尝试递归解析DTO的结构,但DTO只是用于数据传输的普通类,没有被标记为Mongoose可识别的Schema类型,导致TransformOperationExecutor在转换过程中陷入无限递归,最终触发栈溢出。
简单来说:Mongoose需要明确的Schema定义(要么是基础类型,要么是Mongoose子Schema),而DTO不能直接作为Schema的属性类型使用。
解决方案
你需要把ProductInCartDto转换为Mongoose的子Schema,或者在@Prop()中明确指定MongoDB能识别的类型结构。
方案1:定义子Schema类
把ProductInCartDto改成带@Schema()装饰器的子Schema类:
// product-in-cart.schema.ts import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; @Schema() export class ProductInCart { @Prop({ required: true }) storeId: number; @Prop({ type: Map, of: Number, required: true }) productList: Map<number, number>; } export const ProductInCartSchema = SchemaFactory.createForClass(ProductInCart);
然后修改Cart Schema:
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; import { ProductInCart, ProductInCartSchema } from "./product-in-cart.schema"; @Schema({ collection: 'carts', timestamps: true }) export class Cart { @Prop({ required: true }) userId: number; @Prop({ type: [ProductInCartSchema], default: [] }) products: ProductInCart[]; } export const CartSchema = SchemaFactory.createForClass(Cart);
方案2:直接在@Prop中指定类型结构
如果不想单独定义子Schema类,可以直接在@Prop()中声明数组元素的结构:
@Schema({ collection: 'carts', timestamps: true }) export class Cart { @Prop({ required: true }) userId: number; @Prop({ type: [ { storeId: { type: Number, required: true }, productList: { type: Map, of: Number, required: true } } ], default: [] }) products: Array<{ storeId: number; productList: Map<number, number> }>; }
这两种方案都能让Mongoose正确识别数组元素的结构,避免class-transformer的递归转换错误。
内容的提问来源于stack exchange,提问作者Long
相关产品推荐
相关产品推荐

