MongoDB Compass导出JSON命令行insertMany日期类型异常问题
核心逻辑说明:Compass导出的带$date、$numberLong字段的内容属于MongoDB扩展JSON(Canonical模式),通用JSON解析器无法识别这类类型标记,只有MongoDB官方配套的导入/解析工具能正确转换为对应BSON类型。
方案1:优先使用官方命令行工具完成全流程(最稳定,零类型转换问题)
直接抛弃Compass GUI导出/手动拼insertMany的逻辑,用MongoDB自带的mongoexport、mongoimport命令行工具完成迁移,全程自动保留所有BSON类型(日期、ObjectId、长整型、Decimal等都不会出错)。
- 从Dev环境导出集合命令:
mongoexport --uri="mongodb://<Dev环境Mongo连接地址>/<数据库名>" --collection="<目标集合名>" --out=export_data.json --jsonFormat=canonical - 导入到UAT环境命令:
mongoimport --uri="mongodb://<UAT环境Mongo连接地址>/<数据库名>" --collection="<目标集合名>" --file=export_data.json --jsonFormat=canonical
参数提示:如果需要覆盖UAT原有集合数据,可以加--drop参数(导入前先删除原有集合);如果需要增量更新可以加--mode=upsert参数。
方案2:复用已有Compass导出的JSON文件,用官方EJSON解析器处理后插入
如果你已经用Compass导出了文件,不想重新导出,只需要在插入前用MongoDB官方的扩展JSON解析工具处理文件即可,禁止直接用原生JSON.parse()解析这类扩展JSON文件。
场景A:在mongosh命令行中直接执行导入
进入mongosh连接UAT环境后,执行以下命令即可:
const fs = require('fs'); // 用内置EJSON解析器识别所有类型标记 const docs = EJSON.parse(fs.readFileSync('<你的Compass导出JSON文件路径>', 'utf8')); db.<目标集合名>.insertMany(docs);
场景B:写Node.js脚本执行导入
使用MongoDB官方Node.js驱动自带的EJSON模块处理即可:
const { MongoClient, EJSON } = require('mongodb'); const fs = require('fs'); async function importToUat() { const client = new MongoClient('mongodb://<UAT环境Mongo连接地址>'); await client.connect(); const collection = client.db('<数据库名>').collection('<目标集合名>'); const rawContent = fs.readFileSync('<你的Compass导出JSON文件路径>', 'utf8'); const docs = EJSON.parse(rawContent); await collection.insertMany(docs); await client.close(); } importToUat();
方案3:自定义转换逻辑(不推荐,容易漏类型)
如果以上方案都无法使用,可以自行遍历导出的JSON文档,匹配特殊类型结构手动转换,比如把{"$date": {"$numberLong": "1650603600000"}}替换为new Date(1650603600000),但这类方式需要自行覆盖ObjectId、长整型、正则、Decimal128等所有特殊BSON类型,容易出现遗漏导致数据错误,非必要不选择。
补充说明:Compass GUI导入时无异常,是因为Compass导入模块内置了和上述工具一致的EJSON解析逻辑,并非导出的JSON文件可以被通用JSON解析器直接识别。
内容的提问来源于stack exchange,提问作者Slow Snail

