直接迁移mongodb json文档到mysql 8.0需分层处理:先解析结构、映射bson类型(如objectid转char(24)、isodate用str_to_date解析),再按jsonl样本生成合理表结构,最后批量插入;json_table()仅适用于已存入mysql的json字段或字符串常量,不支持外部文件或流式读取。

ObjectId、Date、BinData)在 MySQL 中没有原生对应,硬塞会丢数据或报错。必须分层处理:先解析结构,再映射类型,最后按需建表或展开。
用 JSON_TABLE() 直接查 MongoDB 导出的 JSON 文件?不行
MySQL 8.0 的 JSON_TABLE() 只能处理「已存入 MySQL 表中的 JSON 字段」,或者你手动把整个 JSON 文档作为字符串常量传进去(比如 '{"a":1,"b":{"c":2}}')。它不支持从外部文件、MongoDB 连接或流式数据源实时读取。常见错误是误以为 JSON_TABLE() 能当 ETL 工具用,结果卡在 Unknown column 'xxx' in 'field list' 或 Invalid JSON text 上。
- 它只接受单个 JSON 值(标量或对象/数组),不是多行 JSONL 文件
-
expr参数不支持LOAD_FILE()以外的外部路径,且LOAD_FILE()要求文件在 MySQL 服务端、有FILE权限、且不能超max_allowed_packet - 嵌套过深(如
$.user.profile.address.city)时,COLUMNS里写NESTED PATH容易漏层级或类型推断失败
推荐路径:MongoDB → JSONL 文件 → MySQL 8.0 表结构 + 批量插入
这是最可控、可调试、适配复杂嵌套的方案。关键不在“快”,而在“字段不丢、类型不错、空值不崩”。
- 用
mongoexport --type=json --jsonArray=false --pretty=false导出为每行一个 JSON 对象(JSONL),避免大数组内存溢出 - 用 Python 脚本预扫描样本(比如前 1000 行),识别字段存在性、类型混合(如
"age": 25和"age": "N/A")、嵌套深度,生成 MySQLCREATE TABLE语句(JSON类型字段留作兜底,VARCHAR(255)拆开存) - 对
ObjectId字段,统一转成CHAR(24);对ISODate,用STR_TO_DATE(doc->>'$.created_at', '%Y-%m-%dT%H:%i:%s.%fZ')解析(注意时区) - 批量插入用
INSERT INTO ... VALUES (...), (...), ...,每批 ≤ 1000 行,避开max_allowed_packet限制
如果数据已进 MySQL 但存为 JSON 字段,怎么展开成关系列?
这时 JSON_TABLE() 才真正派上用场——前提是你的 JSON 结构相对稳定。例如 MongoDB 导出后存进了 raw_data.doc JSON 字段:
SELECT u.id, u.name, a.city, a.zip
FROM raw_data,
JSON_TABLE(
doc,
'$' COLUMNS (
id VARCHAR(24) PATH '$._id',
name VARCHAR(100) PATH '$.name',
NESTED PATH '$.address' COLUMNS (
city VARCHAR(100) PATH '$.city',
zip VARCHAR(20) PATH '$.zip'
)
)
) AS u;
- 别忘了给
doc字段加GENERATED COLUMN或索引,否则全表扫描 JSON 解析极慢 -
ON EMPTY NULL必须显式声明,否则缺失字段会触发ERROR ON ERROR默认行为(语句中断) - MySQL 8.0.27+ 支持大小写不敏感列名匹配,但建议导出时统一小写,避免
$.PostId和postid匹配失败











