Node.js中TypeError循环引用转JSON问题排查与解决
问题描述
在通过API从MongoDB获取用户数据时,抛出TypeError: Converting circular structure to JSON错误,错误栈如下:
TypeError: Converting circular structure to JSON --> starting at object with constructor 'MongoClient' | property 's' -> object with constructor 'Object' | property 'sessionPool' -> object with constructor 'ServerSessionPool' --- property 'client' closes the circle at JSON.stringify (<anonymous>) at stringify (C:\Users\Asus\Desktop\LetsChat App\node_modules\express\lib\response.js:1150:12) at ServerResponse.json (C:\Users\Asus\Desktop\LetsChat App\node_modules\express\lib\response.js:271:14) at C:\Users\Asus\Desktop\LetsChat App\backend\controllers\authcontrollers.js:71:9 at asyncUtilWrap (C:\Users\Asus\Desktop\LetsChat App\node_modules\express-async-handler\index.js:3:20) at Layer.handle [as handle_request] (C:\Users\Asus\Desktop\LetsChat App\node_modules\express\lib\router\layer.js:95:5) at next (C:\Users\Asus\Desktop\LetsChat App\node_modules\express\lib\router\route.js:144:13) at C:\Users\Asus\Desktop\LetsChat App\backend\middleware\authentication.js:15:13 at processTicksAndRejections (node:internal/process/task_queues:96:5)
对应的API实现代码:
exports.getallusers = asyncHandler(async (req, res) => { const keyword = req.query.search ? { $or: [ { name: { $regex: req.query.search, $options: "i" } }, { email: { $regex: req.query.search, $options: "i" } } ] } : {} const users = USER.find(keyword).find({ _id: { $ne: req.user._id } }); res.json({ users }) })
问题排查与解决方法
问题根源
USER.find(...)返回的是Mongoose的Query对象,并非实际的查询结果数组。该Query对象内部包含MongoDB客户端的引用,存在循环依赖关系,当Express用res.json()尝试将其序列化为JSON时,就会触发循环结构的报错。
解决步骤
需要通过await执行Query对象(或配合exec()方法显式执行),等待查询完成拿到实际的用户数据数组后,再返回给前端:
修正代码方案一:直接await Query对象
exports.getallusers = asyncHandler(async (req, res) => { const keyword = req.query.search ? { $or: [ { name: { $regex: req.query.search, $options: "i" } }, { email: { $regex: req.query.search, $options: "i" } } ] } : {} // 用await执行查询,获取实际的用户数据数组 const users = await USER.find(keyword).find({ _id: { $ne: req.user._id } }); res.json({ users }) })
修正代码方案二:用exec()显式执行查询
exports.getallusers = asyncHandler(async (req, res) => { const keyword = req.query.search ? { $or: [ { name: { $regex: req.query.search, $options: "i" } }, { email: { $regex: req.query.search, $options: "i" } } ] } : {} // 用exec()显式执行查询,await获取结果 const users = await USER.find(keyword).find({ _id: { $ne: req.user._id } }).exec(); res.json({ users }) })
两种写法效果一致,都是等待MongoDB查询完成,拿到可正常序列化的普通JavaScript对象数组,彻底避免循环引用问题。
内容的提问来源于stack exchange,提问作者Sanyam Kapoor
相关产品推荐
相关产品推荐

