如何读取包含带数据类型括号值的非标准JSON文件?
哈哈,这个坑我踩过好多次——你手里的根本不是标准JSON,是MongoDB导出的那种带自定义类型标记的扩展格式,标准JSON解析器当然会报错。别慌,给你几个结构化的处理方案,按需选:
方法1:快速文本预处理(适合简单场景)
如果只是想把数据读出来,不需要保留原始类型信息,直接用正则把ISODate("xxx")、ObjectId("xxx")这类标记替换成标准字符串就行。
举个Python实现的例子:
import re import json def fix_mongo_json(raw_text): # 把ISODate("时间字符串")替换成纯字符串 text = re.sub(r'ISODate\("([^"]+)"\)', r'"\1"', raw_text) # 把ObjectId("ID字符串")替换成纯字符串 text = re.sub(r'ObjectId\("([^"]+)"\)', r'"\1"', text) return text # 使用示例 with open('your_file.json', 'r', encoding='utf-8') as f: raw_content = f.read() processed_content = fix_mongo_json(raw_content) parsed_data = json.loads(processed_content)
要是你想保留类型信息(比如之后要还原成MongoDB的类型),可以把替换规则改成生成带类型标识的对象:
text = re.sub(r'ISODate\("([^"]+)"\)', r'{"$type": "ISODate", "$value": "\1"}', raw_text) text = re.sub(r'ObjectId\("([^"]+)"\)', r'{"$type": "ObjectId", "$value": "\1"}', raw_text)
方法2:用MongoDB官方工具/驱动(最靠谱的原生方案)
如果这个文件是直接从MongoDB导出的,那最稳妥的方式是用官方工具重新导出成标准JSON,或者直接用驱动读取数据,而不是处理这种非标准文件。
用mongoexport导出标准JSON
在终端里执行:
mongoexport --db 你的数据库名 --collection 你的集合名 --output standard_json_file.json
导出的文件就是标准JSON,直接用任何解析器都能读。
用Python的pymongo直接读取数据
如果能连接到MongoDB,直接读数据再转成标准JSON更省心:
from pymongo import MongoClient import json from datetime import datetime # 连接MongoDB client = MongoClient('mongodb://localhost:27017/') db = client['你的数据库名'] collection = db['你的集合名'] # 读取数据并转换为标准JSON格式 def serialize_mongo_doc(doc): # 把ObjectId转成字符串 if '_id' in doc: doc['_id'] = str(doc['_id']) # 把ISODate转成ISO格式字符串 for key, value in doc.items(): if isinstance(value, datetime): doc[key] = value.isoformat() return doc # 读取所有文档并序列化 all_docs = list(collection.find()) standard_data = [serialize_mongo_doc(doc) for doc in all_docs] # 保存成标准JSON文件 with open('standard_output.json', 'w', encoding='utf-8') as f: json.dump(standard_data, f, indent=2)
方法3:自定义JSON解码器(保留类型信息)
如果必须处理现有文件,还想把ISODate转成Python的datetime对象、ObjectId转成bson的ObjectId对象,可以结合预处理和自定义解码器:
import re import json from datetime import datetime from bson.objectid import ObjectId def decode_mongo_types(obj): # 识别我们预处理时加的$type标记 if '$type' in obj: if obj['$type'] == 'ISODate': # 把ISO字符串转成datetime对象 return datetime.fromisoformat(obj['$value'].replace('Z', '+00:00')) elif obj['$type'] == 'ObjectId': # 转成ObjectId对象 return ObjectId(obj['$value']) return obj # 先预处理文本,把非标准类型转成带标记的对象 raw_text = open('your_file.json', 'r', encoding='utf-8').read() processed_text = re.sub(r'ISODate\("([^"]+)"\)', r'{"$type": "ISODate", "$value": "\1"}', raw_text) processed_text = re.sub(r'ObjectId\("([^"]+)"\)', r'{"$type": "ObjectId", "$value": "\1"}', processed_text) # 用自定义解码器解析 parsed_data = json.loads(processed_text, object_hook=decode_mongo_types)
这样解析后的数据里,原来的ISODate会变成Python的datetime,ObjectId会变成bson的ObjectId,方便后续和MongoDB交互。
内容的提问来源于stack exchange,提问作者HermanK




