Next.js App Router中MongoDB _id转可序列化对象传客户端组件
解决Next.js App Router中MongoDB数据传递的_id转换问题
问题背景
Warning: Only plain objects can be passed to Client Components from Server Components. Objects with toJSON methods are not supported. Convert it manually to a simple value before passing it to props. {_id: {}, userId: ..., userMode: ... }
在Next.js App Router的服务器组件中从MongoDB获取数据后传递给客户端组件时,由于MongoDB文档的_id是ObjectId对象(自带toJSON方法),不符合客户端组件仅接受纯对象的要求,手动逐个页面处理转换过于繁琐。
更优解决方案
1. 查询时通过投影直接转换_id
在MongoDB查询阶段,用投影语法将_id直接转为字符串,返回的结果就是纯对象,无需后续手动处理:
async function getData() { const { user } = await getSession(); const { db } = await connectToDatabase(); // 将_id转为字符串并重命名为id,同时隐藏原_id字段 const strategy = await db.collection("pricing").findOne( { userId: user.sub }, { projection: { id: { $toString: "$_id" }, _id: 0, userId: 1, userMode: 1 } } ); return { strategy }; }
如果要保留_id字段并直接转为字符串,可修改投影规则:
const strategy = await db.collection("pricing").findOne( { userId: user.sub }, { projection: { _id: { $toString: "$_id" }, userId: 1, userMode: 1 } } );
2. 封装通用转换工具函数
创建可复用的工具函数,批量处理单个Mongo文档或文档数组,自动转换_id:
// utils/mongoTransform.js export function transformDoc(doc) { if (!doc) return null; return { ...doc, id: doc._id.toString(), _id: doc._id.toString() // 可选:直接替换原_id字段为字符串 }; } export function transformDocs(docs) { return Array.isArray(docs) ? docs.map(transformDoc) : []; }
在服务器组件中调用:
import { transformDoc } from '@/utils/mongoTransform'; async function getData() { const { user } = await getSession(); const { db } = await connectToDatabase(); const strategy = await db.collection("pricing").findOne({ userId: user.sub }); return { strategy: transformDoc(strategy) }; }
3. 全局配置MongoDB客户端自动转换
在MongoDB连接配置中,添加全局转换规则,让所有查询返回的_id自动转为字符串:
// lib/mongodb.js import { MongoClient } from 'mongodb'; const client = new MongoClient(process.env.MONGODB_URI, { bsonOptions: { serialize: { transform(doc) { if (doc._id) doc._id = doc._id.toString(); return doc; } } } }); export async function connectToDatabase() { await client.connect(); const db = client.db(process.env.MONGODB_DB); return { db, client }; }
此方案会对全项目所有MongoDB查询生效,适合统一要求_id为字符串的场景。
总结
三种方案各有适用场景:
- 投影转换适合单查询的定制化需求;
- 工具函数适合灵活复用、按需调整转换规则;
- 全局配置适合全项目统一转换逻辑,彻底消除重复代码。
内容的提问来源于stack exchange,提问作者dougajmcdonald
相关产品推荐
相关产品推荐

