mongosh用--eval输出合法JSON遇循环结构报错的问题咨询
我有一个名为ftest的MongoDB数据库,其中entities集合仅包含一个文档。执行以下mongosh命令可正常得到JavaScript格式的输出:
$ mongosh mongodb://localhost:27017/ftest --eval 'db.entities.find()' --quiet
输出结果:
[ { _id: { id: 'E1', type: 'E', servicePath: '/' }, attrNames: [ 'position' ], attrs: { position: { value: { type: 'Point', coordinates: [ '5.5', '-6.6' ] }, type: 'geo:json', creDate: 1702639380.716183, modDate: 1702639380.716183, mdNames: [] } }, creDate: 1702639380.716183, modDate: 1702639380.716183, location: { attrName: 'position', coords: { type: 'Point', coordinates: [ 5.5, -6.6 ] } }, lastCorrelator: '4e2f7a0e-9b3c-11ee-98d3-080027cd35f1' } ]
但我需要标准JSON格式的输出(上述JS格式无法通过常规JSON验证工具的校验)。尝试添加--json relaxed或--json canonical选项时,出现循环结构转换错误:
执行命令:
$ mongosh mongodb://localhost:27017/ftest --eval 'db.entities.find()' --quiet --json relaxed
错误输出:
{ "message": "Converting circular structure to EJSON:\n (root) -> _mongo -> __serviceProvider -> mongoClient -> s -> sessionPool -> client\n \\\-------------------------------/", "stack": "BSONError: Converting circular structure to EJSON:\n (root) -> _mongo -> __serviceProvider -> mongoClient -> s -> sessionPool -> client\n \\\-------------------------------/\n at ft (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:983314)\n at /tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:984642\n at ft (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:985421)\n at /tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:984642\n at ft (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:985421)\n at /tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:984642\n at ft (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:985421)\n at /tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:984642\n at ft (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:985421)\n at /tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:984642\n at ft (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:985421)\n at /tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:984642\n at ft (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:985421)\n at Object.yt [as stringify] (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:1960:986405)\n at t.formatForJSONOutput (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:10:53732)\n at CliRepl.loadCommandLineFilesAndEval (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:10:32114)\n at async CliRepl.start (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:10:29909)\n at async w (/tmp/m/boxednode/mongosh/node-v20.9.0/out/Release/node:10:80067)", "name": "BSONError" }
执行--json canonical选项的命令时,报错内容完全一致:
$ mongosh mongodb://localhost:27017/ftest --eval 'db.entities.find()' --quiet --json canonical
我确认自身文档不存在循环依赖,因此无法理解报错原因,现咨询两个问题:
- 为何在relaxed和canonical模式下会出现该报错?
- 如何让mongosh输出标准JSON而非JavaScript对象/数组?
解答
问题1:报错原因
db.entities.find()返回的是游标对象,并非直接的文档数据。当添加--json参数时,mongosh会尝试序列化整个游标对象(包含内部的MongoDB客户端连接信息),而游标对象内部存在循环引用(比如客户端连接与会话池互相引用),因此触发了循环结构转换错误。
不加--json参数时,mongosh会自动遍历游标并输出文档的JS格式,不会序列化游标本身;但添加--json后,它会直接序列化eval命令返回的原始对象(即游标),而非游标指向的文档数据。
问题2:输出标准JSON的方法
需要先将游标转换为文档数组,再让mongosh序列化该数组,常用方法有三种:
方法1:使用.toArray()转换游标
修改--eval中的命令,将游标转为数组:
mongosh mongodb://localhost:27017/ftest --eval 'db.entities.find().toArray()' --quiet --json relaxed
此命令会先将游标中的文档转为数组,再输出符合标准JSON规范的relaxed格式内容。
方法2:结合JSON.stringify手动序列化
如果需要更灵活的控制,可以直接用JSON.stringify处理文档:
mongosh mongodb://localhost:27017/ftest --eval 'JSON.stringify(db.entities.find().toArray())' --quiet
这种方式直接输出标准JSON字符串,无需依赖--json参数。
方法3:使用mongoexport工具
如果仅需导出数据,推荐使用专门的mongoexport工具,它默认输出标准JSON:
mongoexport --uri="mongodb://localhost:27017/ftest" --collection=entities --out=entities.json
该工具更适合批量导出场景,输出的JSON完全符合验证标准。
内容的提问来源于stack exchange,提问作者fgalan

