应优先用 mongodump + jq 或 mongo shell 流式处理替代 mongoexport --fields;嵌套字段需用 .$oid 提取 ID、?. 防空、map 保证作用域独立;大数据量须 --stream 或流式导出;导出后必须验证字段一致性与空值分布。
用 jq 精准提取字段再导出,别直接 mongoexport 硬塞
绝大多数人想备份 mongodb 里某个集合的特定字段(比如只导出 _id、name、status),第一反应是加 --fields 参数。但 mongoexport 的 --fields 只支持扁平字段,遇到嵌套对象(如 user.profile.email)或数组元素(如 tags[0])就失效,还会静默丢数据。
真正可控的做法是:先用 mongodump 导出 BSON,再用 jq 做结构裁剪。或者更轻量——直接用 mongo shell + printjson + jq 流式处理:
mongo yourdb --eval "db.collection.find({status: 'active'}, {_id:1, name:1, 'user.email':1}).toArray()" --quiet | jq -c 'map({id: ._id.\$oid, name: .name, email: .user.email})'- 注意:
_id是 ObjectId 类型,必须用.\$oid提取字符串,否则jq会报错Cannot index string with string "_id" - 如果字段可能为空(比如
.user不存在),用.user?.email避免整个对象被过滤掉
导出数组子项时,jq 的 map 和 .[ ] 别混用
常见需求:从每个文档的 history 数组里只取最近一条的 timestamp 和 action。这时候容易写成 .history | map({ts: .timestamp, act: .action}) | .[0],结果发现只导出了第一条文档的 history[0],而不是每条文档都取自己的 history[0]。
关键在作用域层级:
- 错误写法:
jq '.history | map({ts: .timestamp}) | .[0]'—— 先把所有文档的history合并成一个大数组,再取第 0 个 - 正确写法:
jq 'map({id: ._id.\$oid, last: (.history | .[0] // {}) | {ts: .timestamp, act: .action}})'——map作用于顶层数组,每个元素独立处理 - 用
// {}处理history为空或缺失的情况,否则.[0]会返回null,导致字段丢失
导出量大时,避免 mongo --eval 内存爆炸
当集合超过 10 万文档,--eval 会把全部结果 load 进 shell 内存再转 JSON,极易 OOM 或超时。这时必须切到流式导出路径:
- 用
mongosh(新版)配合cursor.forEach()+console.log(JSON.stringify(...)),但要注意换行符和 JSON 合法性 - 更稳方案:用
mongodump --query加过滤,再用mongorestore --dryRun配合自定义脚本解析 BSON 文件(用bsondump或 Pythonbson库) - 如果坚持用
jq,务必加--stream参数:mongoexport ... --jsonFormat=canonical | jq --stream -r 'select(length==2 and .[0]=="_id") | .[1].\$oid',能省 70% 内存
导出后验证结构是否符合预期,光看文件大小没用
很多人导完 output.json 就以为完事,结果下游解析时报 Unexpected token u in JSON —— 实际是某条文档里有个字段值是 undefined,MongoDB 导出时转成了 null,但 jq 某些写法会把它变成 "" 或直接删掉字段,导致 JSON 不对齐。
快速验证建议:
- 抽样检查头 3 行:
head -3 output.json | jq keys,确认字段名一致 - 查空值分布:
jq 'map(select(.email == null)) | length' output.json,和原始查询条件比对是否合理 - 用
jq 'map(type) | unique'确认没有混入字符串、对象、数组三种类型(尤其注意时间字段,Date导出后可能是字符串也可能是嵌套对象)
嵌套深、字段动态变化的 NoSQL 数据,结构一致性永远比导出速度更难保障。多花 30 秒验证,能省掉后续两小时 debug。










