上周四凌晨两点我被电话吵醒,运维说测试环境订单服务全崩了,日志里全是 MongoNetworkError。
排查了半小时才反应过来——这周在做 MongoDB 往金仓迁移的验证,有人把连接串切错环境了。
但说实话,这只是开胃菜。
真正让我掉头发的,是后面两周踩的那些兼容性坑。
先说下为什么要换掉 MongoDB。
我们是个中型电商系统,核心业务数据全存在 MongoDB 5.0 里。1.2 亿条文档,每天写入 300 万左右。
换的原因很现实:今年过等保三级,安全评审那边直接说了,核心数据必须用国产数据库。
选型评估了一圈,金仓(KingbaseES V9)的 JSON/JSONB 支持算是比较完善的,而且有专门的 MongoDB 兼容接口层,理论上迁移成本最低。
我当时心想:不就换个数据源嘛,JSONB 又不是什么新东西,能有多难?
经典立 flag。
第一个坑:嵌套文档查询语法不兼容。
MongoDB 里我们大量用点号路径查嵌套字段,比如查用户默认收货地址:
// MongoDB 原始查询 — 直接复制这段可以在 mongo shell 里跑
db.users.find({
"address.default": true,
"address.city": "北京",
"profile.level": { $gte: 3 }
}).projection({
name: 1,
phone: 1,
"address.$": 1
})
迁到金仓之后,这种点号路径得改写成 JSONB 操作符。
我一开始手动改,改了十几个接口之后感觉不对劲——整个项目里有 200 多个这样的查询。
手改到猴年马月?
于是我让 Kiro 帮我写了个自动转换脚本,把 MongoDB 的查询 DSL 批量转成金仓兼容的 SQL。核心转换逻辑长这样:
# mongo_to_kingbase.py — 直接复制这段,Python 3.9+ 可运行
# 依赖:pip install pymongo psycopg2-binary
import json
import re
def convert_dot_path_to_jsonb(mongo_query: dict, table_name: str = "users") -> str:
"""将 MongoDB 点号路径查询转换为金仓 JSONB 查询"""
conditions = []
operator_map = {
"$gte": ">=",
"$gt": ">",
"$lte": "<=",
"$lt": "<",
"$ne": "!=",
"$eq": "=",
}
for field, value in mongo_query.items():
parts = field.split(".")
if len(parts) == 1:
jsonb_path = f"data->>'{parts[0]}'"
else:
# address.city → data->'address'->>'city'
middle = "->".join(f"'{p}'" for p in parts[:-1])
jsonb_path = f"data->{middle}->>'{parts[-1]}'"
if isinstance(value, dict):
for op, val in value.items():
sql_op = operator_map.get(op, "=")
if isinstance(val, (int, float)):
conditions.append(f"({jsonb_path})::numeric {sql_op} {val}")
else:
conditions.append(f"{jsonb_path} {sql_op} '{val}'")
elif isinstance(value, bool):
...