mongoose-autopopulate icon indicating copy to clipboard operation
mongoose-autopopulate copied to clipboard

can't use mongoose-autopopulate on recursively nested schema : Maximum call stack size exceeded

Open liitfr opened this issue 2 years ago • 1 comments

Hello !

First of all, thanks for mongoose & mongoose-autopopulate. I tried to reduce my example to its simplest form. I'm using Nestjs as backend framework.

Reproduction schema is following:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import {
  Document as MongooseDocument,
  Schema as MongooseSchema,
} from 'mongoose';

interface SectionI {
  template?: SectionTemplateI;
  text: string;
  date: Date;
  subSections?: SectionI[];
}

interface SectionTemplateI {
  section: SectionI;
}

export type SectionDocument = Section & MongooseDocument;

@Schema()
export class Section implements SectionI {
  @Prop({
    type: MongooseSchema.Types.ObjectId,
    ref: 'SectionTemplate',
    autopopulate: false,
    required: false,
  })
  template?: SectionTemplateI;

  @Prop({ type: String, required: true })
  text: string;

  @Prop({ type: Date, required: true })
  date: Date;

  subSections?: SectionI[];
}

export const SectionSchema = SchemaFactory.createForClass(Section);

SectionSchema.add({
  subSections: {
    type: [SectionSchema],
    required: false,
  },
});

export type SectionTemplateDocument = SectionTemplate & MongooseDocument;

@Schema()
export class SectionTemplate implements SectionTemplateI {
  @Prop({ type: SectionSchema, required: true })
  section: SectionI;
}

export const SectionTemplateSchema =
  SchemaFactory.createForClass(SectionTemplate);

As you can see, subSections are nested, not relations. I believe it's the root cause of this issue, but don't know if it's expected behavior, and if so, what is the workaround solution.

autopopulate is enabled globally, by following nestjs instruction :

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';

import { AppController } from './app.controller';
import { AppService } from './app.service';

import { SectionTemplate, SectionTemplateSchema } from './app.schema';

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://localhost:27018/tbd', {
      connectionFactory: (connection) => {
        // eslint-disable-next-line @typescript-eslint/no-var-requires
        connection.plugin(require('mongoose-autopopulate'));
        return connection;
      },
    }),
    MongooseModule.forFeature([
      { name: SectionTemplate.name, schema: SectionTemplateSchema },
    ]),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Nest throws following error when starting app :

[Nest] 4530  - 10/17/2022, 6:19:11 PM   ERROR [ExceptionHandler] Maximum call stack size exceeded
RangeError: Maximum call stack size exceeded
    at /home/foo/code/test-mongoose/node_modules/mongoose-autopopulate/index.js:238:27
    at Schema.eachPath (/home/foo/code/test-mongoose/node_modules/mongoose/lib/schema.js:1340:5)
    at eachPathRecursive (/home/foo/code/test-mongoose/node_modules/mongoose-autopopulate/index.js:238:10)
    at /home/foo/code/test-mongoose/node_modules/mongoose-autopopulate/index.js:241:7
    at Schema.eachPath (/home/foo/code/test-mongoose/node_modules/mongoose/lib/schema.js:1340:5)
    at eachPathRecursive (/home/foo/code/test-mongoose/node_modules/mongoose-autopopulate/index.js:238:10)
    at /home/foo/code/test-mongoose/node_modules/mongoose-autopopulate/index.js:241:7
    at Schema.eachPath (/home/foo/code/test-mongoose/node_modules/mongoose/lib/schema.js:1340:5)
    at eachPathRecursive (/home/foo/code/test-mongoose/node_modules/mongoose-autopopulate/index.js:238:10)
    at /home/foo/code/test-mongoose/node_modules/mongoose-autopopulate/index.js:241:7

liitfr avatar Oct 17 '22 16:10 liitfr

I also share this example's dependencies

{
  "dependencies": {
    "@nestjs/apollo": "^10.1.3",
    "@nestjs/common": "^9.0.0",
    "@nestjs/core": "^9.0.0",
    "@nestjs/graphql": "^10.1.3",
    "@nestjs/mongoose": "^9.2.0",
    "@nestjs/platform-express": "^9.0.0",
    "apollo-server-express": "^3.10.3",
    "graphql": "^16.6.0",
    "mongoose": "^6.6.5",
    "mongoose-autopopulate": "^0.16.1",
    "reflect-metadata": "^0.1.13",
    "rimraf": "^3.0.2",
    "rxjs": "^7.2.0"
  },
  "devDependencies": {
    "@nestjs/cli": "^9.0.0",
    "@nestjs/schematics": "^9.0.0",
    "@nestjs/testing": "^9.0.0",
    "@types/express": "^4.17.13",
    "@types/jest": "28.1.8",
    "@types/node": "^16.0.0",
    "@types/supertest": "^2.0.11",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0",
    "eslint": "^8.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^4.0.0",
    "jest": "28.1.3",
    "prettier": "^2.3.2",
    "source-map-support": "^0.5.20",
    "supertest": "^6.1.3",
    "ts-jest": "28.0.8",
    "ts-loader": "^9.2.3",
    "ts-node": "^10.0.0",
    "tsconfig-paths": "4.1.0",
    "typescript": "^4.7.4"
  },
}

liitfr avatar Oct 17 '22 16:10 liitfr

Fixed here: https://github.com/mongodb-js/mongoose-autopopulate/pull/106

vkarpov15 avatar Jan 18 '23 21:01 vkarpov15