You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js13.5服务端动作中Mongoose Populate触发栈溢出错误排查

Next.js 13.5服务端动作中Mongoose populate导致调用栈溢出问题

在Next.js 13.5的服务端动作里,执行Mongoose的find查询并返回结果时,碰到了Maximum call stack size exceeded(调用栈超出最大值)错误。移除Mongoose的populate方法后错误消失,所以问题根源锁定在populate操作上。

报错信息

Error: Maximum call stack size exceeded

Call Stack
String.replace
<anonymous>
_e
file:///C:/Users/hossein/homebnb/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (1:447398)
Re
file:///C:/Users/hossein/homebnb/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (1:448056)
Re
file:///C:/Users/hossein/homebnb/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (1:449122)
Re
file:///C:/Users/hossein/homebnb/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (1:449122)
Re
file:///C:/Users/hossein/homebnb/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (1:449122)
Re
file:///C:/Users/hossein/homebnb/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (1:449122)
Re
file:///C:/Users/hossein/homebnb/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (1:449122)

服务端动作代码

import { Types } from "mongoose";
import Reservation from "@/models/Reservation";

interface IParams {
  listingId?: string;
  userId?: string;
  authorId?: string;
}

export default async function getReservations(params: IParams) {
  const { listingId, userId, authorId } = params;

  const query: any = {};

  if (listingId) {
    query.listingId = new Types.ObjectId(listingId);
  }

  if (userId) {
    query.userId = userId;
  }

  if (authorId) {
    query.listing = { userId: authorId };
  }

  console.log("QUERY: " + JSON.stringify(query));
  try {
    const reservations = await Reservation.find(query)
      .populate({ path: "userId", select: "name" })

      .then((p) => {
        return p;
      })
      .catch((error) => console.log(error));

    console.log("REsSSSSS" + reservations);

    return reservations;
  } catch (error: any) {
    throw new Error(error);
  }
}

解决方法

这个问题本质是Mongoose返回的文档是带有内部方法和循环引用的Mongoose对象,Next.js在序列化这些对象时会陷入无限递归,最终导致栈溢出。特别是populate操作引入关联文档后,循环引用的概率会更高。

可以通过以下几种方式解决:

  • 使用.lean()返回纯JS对象:让Mongoose直接返回普通JavaScript对象,避免携带Mongoose的内部属性和方法,这是最直接的解决方案:
    const reservations = await Reservation.find(query)
      .populate({ path: "userId", select: "name" })
      .lean(); // 新增lean()方法
    
  • 手动序列化清理:如果需要保留部分Mongoose特性,可以手动将结果转换为JSON再解析回对象,强制剥离循环引用:
    const reservations = await Reservation.find(query)
      .populate({ path: "userId", select: "name" });
    const plainReservations = JSON.parse(JSON.stringify(reservations));
    return plainReservations;
    
  • 检查模型双向引用:排查Reservation和User模型是否存在双向关联(比如User模型也关联了Reservation),如果是,需要在populate时严格限制返回字段,或者调整模型设计移除不必要的双向引用。

另外,代码中.then(p => p)属于冗余代码,直接删除即可简化结构。

内容的提问来源于stack exchange,提问作者Hossein Ansari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 20:49:57