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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:10:27