You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB导入含Decimal类型JSON数据遇$numberDecimal报错求助

解决MongoDB Python插入Decimal128字段的Schema验证问题

咱们先直接戳中你遇到的核心痛点:你的test_dec集合Schema要求IdDecimal是MongoDB的decimal类型(对应Python里的Decimal128),但在代码处理JSON数据时,不管是原生JSON解析、MongoDB扩展JSON语法还是RawBSONDocument的使用,都没做好类型匹配,导致各种报错。

问题根源拆解

  1. $numberDecimal的无效性:直接在JSON里写{"$numberDecimal": "2.33"}会触发key '$numberDecimal' must not start with '$'——因为原生json.load只会把它当成普通键值对,而MongoDB不允许普通字段键以$开头(那是操作符的专属前缀)。
  2. Decimal128的JSON解码矛盾:JSON本身没有Decimal类型,你没法直接把Python的Decimal128('2.33')写进JSON文件,必须在代码里完成字符串到Decimal128对象的转换。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 14:47:34