PyMongo从Python字典向MongoDB存储小数与日期的问题排查
问题解答
1. 日期存储:是否需要转为日期类型?
从你的测试结果能看到:
myDateInsertedFmt是格式化后的字符串,存储为 MongoDB 的字符串类型myDateInsertedNow是 Pythondatetime对象,自动被编码为 MongoDB 的ISODate类型
建议优先存储为日期类型,原因:
- 支持日期范围查询、按日期排序等操作
- MongoDB 内部以 UTC 存储,自动处理时区转换
- 避免字符串格式不一致引发的问题
如果需要展示格式化后的日期,可在查询后再做字符串格式化,不必在存储阶段处理。
2. 货币存储:是否必须用浮点型?
不需要。直接用 Python decimal.Decimal 报错,是因为 PyMongo 默认不支持编码该类型,但 MongoDB 提供了 Decimal128 类型,专门用于高精度数值存储,完全适配货币场景(可避免浮点型的精度丢失问题)。
解决方法:
使用 bson.Decimal128 类型转换:
from decimal import Decimal from bson import Decimal128 row_dict['myCurrencyDecimal'] = Decimal128(Decimal('25.97'))
存储后 MongoDB 会以 Decimal128("25.97") 的形式保存,完美保留精度。
3. 如何处理带引号的数字(JSON/CSV 中的字符串类型数字)
无论是 JSON 中带引号的数字,还是 CSV 解析后得到的字符串型数字,都需要在插入 MongoDB 前转换为对应数值类型,具体实现:
针对 CSV 解析:
解析时对每个字段尝试转换为数值类型:
import csv from decimal import Decimal def convert_to_numeric(value): try: return int(value) except ValueError: try: return Decimal(value) # 用Decimal处理小数,避免浮点精度问题 except ValueError: return value # 无法转换则保留字符串 with open('data.csv', 'r') as f: reader = csv.DictReader(f) for row in reader: for key, val in row.items(): row[key] = convert_to_numeric(val) db_collection.insert_one(row)
针对带引号数字的 JSON:
解析 JSON 后遍历数据转换字符串型数字:
import json from decimal import Decimal def convert_to_numeric(value): try: return int(value) except ValueError: try: return Decimal(value) except ValueError: return value def parse_json_with_numeric(json_str): data = json.loads(json_str) for key, val in data.items(): if isinstance(val, str): data[key] = convert_to_numeric(val) return data # 示例使用 json_str = '{"key": "test", "myInteger": "21", "myCurrency": "25.97"}' processed_data = parse_json_with_numeric(json_str) db_collection.insert_one(processed_data)
附:你的测试代码及结果
测试代码
from decimal import * from pymongo import MongoClient import datetime # 补充原代码缺失的导入 my_int_a = "21" my_int_b = 21 row_dict = {} row_dict['key'] = 'my string (default)' row_dict['myInteger'] = int(21) row_dict['myInteger2'] = 21 row_dict['myInteger3'] = my_int_a row_dict['myInteger4'] = my_int_b # row_dict['myCurrencyDecimal'] = Decimal(25.97) row_dict['myCurrencyDouble'] = 25.97 row_dict['myDateInsertedFmt'] = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.000Z") row_dict['myDateInsertedNow'] = datetime.datetime.now() db_collection_test_datatypes.insert_one(row_dict) db_collection_test_datatypes.insert_one(row_dict) json_dict = { 'key': 'my json key', 'myInteger': 21, 'myCurrencyDouble': 25.97 } db_collection_test_datatypes.insert_one(json_dict)
查询结果
{ "_id": ObjectId("653052a351416c5223bbeee7"), "key": "my string (default)", "myInteger": NumberInt("21"), "myInteger2": NumberInt("21"), "myInteger3": "21", "myInteger4": NumberInt("21"), "myCurrencyDouble": 25.97, "myDateInsertedFmt": "2023-10-18T16:48:19.000Z", "myDateInsertedNow": ISODate("2023-10-18T16:48:19.411Z") }
{ "_id": ObjectId("65305109485c0394d26e8983"), "key": "my json key", "myInteger": NumberInt("21"), "myCurrencyDouble": 25.97 }
内容的提问来源于stack exchange,提问作者NealWalters
相关产品推荐
相关产品推荐

