Pymongo:无法编码十进制类型的对象。十进制?

在尝试将insert_one插入集合之后。我收到此错误:


bson.errors.InvalidDocument: cannot encode object: Decimal('0.16020'), of type: <class 'decimal.Decimal'>

当 JSON 不包含decimal.Decimal对象时,代码运行良好。如果有解决方案,您能否考虑以递归方式对其进行编码,以使整个 python 字典json_dic兼容以插入到 MongoDB 中(因为条目中有不止一次的类 decimal.Decimal 实例json.dic)。


编辑 1:这是我正在处理的 JSON


import simplejson as json

from pymongo import MongoClient


json_string = '{"A" : {"B" : [{"C" : {"Horz" : 0.181665435,"Vert" : 0.178799435}}]}}'


json_dict = json.loads(json_string)

this_collection.insert_one(json_dict)

这产生 bson.errors.InvalidDocument: cannot encode object: Decimal('0.181665435'), of type: <class 'decimal.Decimal'>


编辑 2:不幸的是,我上面的示例过于简化了我现有的 JSON,@ Belly Buster提供的答案(尽管上面的 Json 可以正常工作)出现错误:


AttributeError: 'decimal.Decimal' object has no attribute 'items'

使用我的实际 JSON,所以我在这里提供完整的 JSON,希望能找出问题所在(也作为屏幕截图):


json_string = 

'

{

  "Setting" : {

    "GridOptions" : {

      "Student" : "HighSchool",

      "Lesson" : 1,

      "Attended" : true

    },

    "Grades" : [

      80,

      50.75

    ],

    "Count" : 2,

    "Check" : "Coursework",

    "Passed" : true

  },

  "Slides" : [

    {

      "Type" : "ABC",

      "Duration" : 1.5

    },

    {

      "Type" : "DEF",

      "Duration" : 0.5

    }

  ],

  "Work" : {

    "Class" : [

      {

        "Time" : 123456789,

        "Marks" : {

          "A" : 50,

          "B" : 100

        }

      }

    ],

    "CourseWorkDetail" : [

      {

        "Test" : {

          "Mark" : 0.987654321

        },

        "ReadingDate" : "Feb162006",

        "Reading" : 300.001,

        "Values" : [

          [

            0.98765

          ],

          [

            -0.98765

          ]

        ]

      },

      {

        "Test" : {

          "Mark" : 0.123456789

        },

        "ReadingDate" : "Jan052010",

        "Reading" : 200.005,

        "Values" : [

          [

            0.12345

          ],

          [

            -0.12345

          ]

        ]

      }

    ]

  },

  "listing" : 5

}

'



www说
浏览 301回答 4
4回答

胡说叔叔

编辑:该convert_decimal()函数将在复杂的 dict 结构中执行 Decimal 到 Decimal128 的转换:import simplejson as jsonfrom pymongo import MongoClientfrom decimal import Decimalfrom bson.decimal128 import Decimal128def convert_decimal(dict_item):&nbsp; &nbsp; # This function iterates a dictionary looking for types of Decimal and converts them to Decimal128&nbsp; &nbsp; # Embedded dictionaries and lists are called recursively.&nbsp; &nbsp; if dict_item is None: return None&nbsp; &nbsp; for k, v in list(dict_item.items()):&nbsp; &nbsp; &nbsp; &nbsp; if isinstance(v, dict):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; convert_decimal(v)&nbsp; &nbsp; &nbsp; &nbsp; elif isinstance(v, list):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for l in v:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; convert_decimal(l)&nbsp; &nbsp; &nbsp; &nbsp; elif isinstance(v, Decimal):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dict_item[k] = Decimal128(str(v))&nbsp; &nbsp; return dict_itemdb = MongoClient()['mydatabase']json_string = '{"A" : {"B" : [{"C" : {"Horz" : 0.181665435,"Vert" : 0.178799435}}]}}'json_dict = json.loads(json_string, use_decimal=True)db.this_collection.insert_one(convert_decimal(json_dict))print(db.this_collection.find_one())给出:{'_id': ObjectId('5ea743aa297c9ccd52d33e05'), 'A': {'B': [{'C': {'Horz': Decimal128('0.181665435'), 'Vert': Decimal128('0.178799435')}}]}}原来的:要将小数转换为 MongoDB 满意的 Decimal128,请将其转换为字符串,然后再转换为 Decimal128。此代码段可能会有所帮助:from pymongo import MongoClientfrom decimal import Decimalfrom bson.decimal128 import Decimal128db = MongoClient()['mydatabase']your_number = Decimal('234.56')your_number_128 = Decimal128(str(your_number))db.mycollection.insert_one({'Number': your_number_128})print(db.mycollection.find_one())给出:{'_id': ObjectId('5ea6ec9b52619c7b39b851cb'), 'Number': Decimal128('234.56')}

收到一只叮咚

Pymongo 无法识别Decimal- 这就是您收到错误的原因。正确的 pymongo 插入是coll.insert_one({"number1": Decimal128('8.916')}).您还需要导入 -from bson import Decimal128现在,如果您想在不更改Decimal为 Decimal128 的情况下处理您的 JSON 文件,您可以修改导入语句。from&nbsp;bson&nbsp;import&nbsp;Decimal128&nbsp;as&nbsp;Decimal coll.insert_one({"number1":&nbsp;Decimal('8.916')})

BIG阳

我建议只添加一个编解码器以在插入时自动转换数据类型。如果您递归地更改数据类型以使用 Decimal128 对象,您可能会破坏与现有代码的兼容性。您可以按照教程在此处的 pymongo 文档中创建一个简单的 decimal.Decimal 编解码器

慕无忌1623718

from bson.decimal128 import Decimal128, create_decimal128_contextfrom decimal import localcontextdecimal128_ctx = create_decimal128_context()with localcontext(decimal128_ctx) as ctx:&nbsp; &nbsp; horiz_val = Decimal128(ctx.create_decimal("0.181665435"))&nbsp; &nbsp; vert_val = Decimal128(ctx.create_decimal("0.178799435"))doc = { 'A': { 'B': [ { 'C': { 'Horiz': horiz_val, 'Vert': vert_val } } ] } }result = collection.insert_one(doc)# result.inserted_idpprint.pprint(list(collection.find()))[ {'A': {'B': [{'C': {'Horiz': Decimal128('0.181665435'),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'Vert': Decimal128('0.178799435')}}]},&nbsp; '_id': ObjectId('5ea79adb915cbf3c46f5d4ae')} ]笔记:PyMongo 的decimal128 - 支持 BSON Decimal128Python 的十进制模块&nbsp;提供对十进制浮点运算的支持。来自 PyMongo 的 decimal128 文档:为确保计算结果始终可以存储为 BSON Decimal128,请使用返回的上下文create_decimal128_context()(注意:如上面的示例代码所示)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python