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

如何读取含无效日期格式的MongoDB游标并忽略错误条目

解决pymongo读取MongoDB时因无效日期触发InvalidBSON异常的问题

问题背景

使用pymongo==3.12.0读取MongoDB数据时,部分文档存在超出Python datetime范围的日期字段(如created字段年份为201244),遍历游标时触发bson.errors.InvalidBSON异常,导致程序中断,无法继续读取后续有效文档。

解决方案

方法1:自定义日期解码器,捕获溢出错误

通过修改BSON编解码器的日期解析逻辑,捕获OverflowError并返回占位值或跳过该字段,避免整个文档解析失败。

import datetime
from bson import codec_options, _millis_to_datetime
from pymongo import MongoClient

def safe_millis_to_datetime(millis):
    try:
        return _millis_to_datetime(millis)
    except OverflowError:
        # 返回占位日期或None,可根据需求调整
        return datetime.datetime(9999, 12, 31)

# 配置自定义编解码器
opts = codec_options.CodecOptions(
    tz_aware=False,
    datetime_converter=safe_millis_to_datetime
)

# 应用编解码器获取集合
client = MongoClient()
db = client["testdb"]
collection = db.get_collection("test", codec_options=opts)

# 执行查询
query = {'modified': {'$gt': datetime.datetime(2020, 7, 22, 6, 35, 51, 859000), '$lte': datetime.datetime(2022, 12, 1, 2, 44, 41, 424501)}}
cursor = collection.find(query).sort("modified", 1).skip(1000).limit(1000)

# 遍历并处理文档
for doc in cursor:
    # 检查是否为占位日期,做跳过或标记处理
    if doc.get("created") == datetime.datetime(9999, 12, 31):
        print(f"跳过无效日期文档: {doc['_id']}")
        continue
    print(doc)

方法2:读取原始BSON字节,逐个解析文档

如果自定义解码器仍无法处理,可直接读取原始BSON响应,逐个解析文档,捕获单个文档的解析异常并跳过。

import bson
from pymongo import MongoClient
import datetime
from bson.errors import InvalidBSON

client = MongoClient()
db = client["testdb"]
collection = db["test"]

query = {'modified': {'$gt': datetime.datetime(2020, 7, 22, 6, 35, 51, 859000), '$lte': datetime.datetime(2022, 12, 1, 2, 44, 41, 424501)}}
cursor = collection.find(query).sort("modified", 1).skip(1000).limit(1000)

# 手动处理查询响应
with client._get_socket(cursor.address) as sock_info:
    msg = cursor._query_message()
    sock_info.send_message(msg)
    reply = sock_info.receive_message()
    
    offset = 0
    while offset < len(reply.data) - 1:
        try:
            doc = bson.BSON(reply.data[offset:]).decode()
            offset += len(doc) + 4  # 跳过BSON长度前缀+文档内容
            print(doc)
        except InvalidBSON:
            offset += 4  # 跳过无效文档的长度字段,继续下一个
            print("跳过无效BSON文档")

方法3:MongoDB端过滤无效日期(推荐)

如果能确定无效日期的规则(如年份超出合理范围),可在查询时直接过滤掉这些文档,从源头避免读取无效数据。

import datetime
from pymongo import MongoClient

client = MongoClient()
db = client["testdb"]
collection = db["test"]

# 查询时同时过滤日期字段在合理范围内的文档
query = {
    'modified': {'$gt': datetime.datetime(2020, 7, 22, 6, 35, 51, 859000), '$lte': datetime.datetime(2022, 12, 1, 2, 44, 41, 424501)},
    'created': {
        '$gte': datetime.datetime(1970, 1, 1),
        '$lte': datetime.datetime(9999, 12, 31)
    }
}

cursor = collection.find(query).sort("modified", 1).skip(1000).limit(1000)

for doc in cursor:
    print(doc)

注意:方法3依赖MongoDB能正常识别无效日期字段,若日期字段的BSON结构已损坏,需使用方法1或方法2处理。

内容的提问来源于stack exchange,提问作者manas pythonic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 17:45:31