Next.js中getStaticProps返回MongoDB数据时的序列化报错问题
你看到的console.log结果具有迷惑性:PostModel.find()返回的不是原生普通JavaScript对象,而是Mongoose Document类的实例。
这类实例的原型链上挂载了大量Mongoose内部逻辑(包括Schema校验状态、文档操作方法、虚拟字段计算逻辑等),这些内容本身不满足JSON序列化要求。控制台打印时会自动把实例格式化成和普通对象一致的输出效果,但不会在打印阶段做序列化校验,所以你没法从console.log的结果里发现异常。
另外countDocuments()返回的是原生数字类型,本身不存在序列化问题,报错来源完全是posts数组里的Document实例。
方案1:使用Mongoose内置lean()查询(最优解)
在Mongoose查询链路最后追加.lean(),Mongoose会跳过文档实例的组装流程,直接返回纯结构的普通JS对象,从根源上消除不可序列化的内容,同时还能提升查询性能:
export const getStaticProps: GetStaticProps = async ( context: GetStaticPropsContext ) => { await connectDb() const count = await PostModel.countDocuments() // 追加.lean(),返回纯普通JS对象 const posts = await PostModel.find().lean() console.log(posts) console.log(count) return { props: { posts, count }, revalidate: 10, } }
补充:如果遇到特殊自定义字段还是有序列化问题,可以加一层
JSON.parse(JSON.stringify(posts))做兜底,强制剥离所有非原生结构。
方案2:手动转换文档实例
如果因为项目逻辑需要保留Mongoose查询的默认行为,可以在拿到查询结果后做一次序列化转义,把类实例转成纯普通对象:
const rawPosts = await PostModel.find() const posts = JSON.parse(JSON.stringify(rawPosts))
Next.js的getStaticProps要求返回的props必须是纯可JSON序列化的原生JS结构,也就是只支持普通对象、数组、字符串、数字、布尔值、null,任何带自定义原型、类实例、函数、Map/Set、Buffer的结构都会触发这类序列化报错,和控制台打印的外观无关。
内容的提问来源于stack exchange,提问作者Dastan

