MongoDB导入含Decimal类型JSON数据遇$numberDecimal报错求助
解决MongoDB Python插入Decimal128字段的Schema验证问题
咱们先直接戳中你遇到的核心痛点:你的test_dec集合Schema要求IdDecimal是MongoDB的decimal类型(对应Python里的Decimal128),但在代码处理JSON数据时,不管是原生JSON解析、MongoDB扩展JSON语法还是RawBSONDocument的使用,都没做好类型匹配,导致各种报错。
问题根源拆解
$numberDecimal的无效性:直接在JSON里写{"$numberDecimal": "2.33"}会触发key '$numberDecimal' must not start with '$'——因为原生json.load只会把它当成普通键值对,而MongoDB不允许普通字段键以$开头(那是操作符的专属前缀)。Decimal128的JSON解码矛盾:JSON本身没有Decimal类型,你没法直接把Python的Decimal128('2.33')写进JSON文件,必须在代码里完成字符串到Decimal128对象的转换。RawBSONDocument的误用:这个类是用来直接处理BSON二进制流的,你把普通Python字典传给它,自然会触发类型错误,它根本不是用来处理JSON转BSON的常规工具。
正确解决方案
步骤1:放弃RawBSONDocument(除非你真的需要处理原始BSON)
你的场景是从JSON文件加载数据插入MongoDB,用默认的文档类就足够了,它会自动处理Python类型到BSON类型的映射,完全没必要画蛇添足用RawBSONDocument。
步骤2:在代码中把JSON里的Decimal值转为Decimal128对象
当用json.load加载JSON后,手动把IdDecimal字段转换成MongoDB认可的Decimal128类型,就能通过Schema验证。
修正后的完整代码
import os import re import io import json from pymongo import MongoClient from bson.decimal128 import Decimal128 # 连接数据库,使用默认文档类即可 client = MongoClient('localhost', 27018) db = client['myDB'] coll = db['test_dec'] other_col = db['free'] # 遍历目标目录的JSON文件 for fname in os.listdir('/mnt/win/load'): # 匹配带数字的文件名(保留你原有的逻辑) if re.findall("\d+", fname): with io.open(fname, encoding="ISO-8859-1") as f: # 用原生json.load加载数据为Python字典 doc_data = json.load(f) # 转换IdDecimal为Decimal128对象,兼容两种JSON格式 decimal_val = doc_data.get('IdDecimal') if isinstance(decimal_val, str): doc_data['IdDecimal'] = Decimal128(decimal_val) elif isinstance(decimal_val, dict) and '$numberDecimal' in decimal_val: doc_data['IdDecimal'] = Decimal128(decimal_val['$numberDecimal']) # 插入文档 coll.insert_one(doc_data) print(f"成功插入文件 {fname} 的数据") # 测试插入示例文档 test = '{"idTitulo":"La pelicula","idRelease":2019}' test_doc = json.loads(test) other_col.insert_one(test_doc) client.close()
支持的两种JSON文件格式
格式1:直接存储Decimal字符串(最简洁)
{ "IdTitulo": "Gremlins", "IdDirector": "Joe Dante", "IdNumber": 6, "IdDecimal": "3.45" }
格式2:兼容MongoDB扩展JSON格式
{ "IdTitulo": "Gremlins", "IdDirector": "Joe Dante", "IdNumber": 6, "IdDecimal": {"$numberDecimal": "3.45" } }
为什么之前的方法失效?
bson.json_util.loads/dumps的冗余操作:你之前用loads(dumps(f, ...))完全是多此一举——把文件对象转成JSON字符串再解析,既浪费性能,还没把生成的$numberDecimal字典转换成Decimal128对象,MongoDB自然不认。RawBSONDocument的场景错配:这个类是给高级场景用的(比如直接读取BSON二进制文件),你用它处理普通Python字典,相当于给自行车装飞机引擎,肯定报错。
验证插入结果
插入完成后,你可以在MongoDB shell里执行以下命令验证:
db.test_dec.find({IdTitulo: "Gremlins"}).pretty()
你会看到IdDecimal字段显示为NumberDecimal("3.45"),且没有Schema验证错误。
内容的提问来源于stack exchange,提问作者powerPixie
相关产品推荐
相关产品推荐

