【问题标题】:Iterating through PyMongo cursor throws InvalidBSON: year is out of range遍历 PyMongo 游标会抛出 InvalidBSON: year is out of range
【发布时间】:2019-04-10 04:21:57
【问题描述】:

我正在使用 PyMongo 简单地迭代 Mongo 集合,但我在处理大型 Mongodb 日期对象时遇到了困难。

例如,如果我的集合中有一些如下所示的数据:

"bad_data" : [ 
            {
                "id" : "id01",
                "label" : "bad_data",
                "value" : "exist",
                "type" : "String",
                "lastModified" : ISODate("2018-06-01T10:04:35.000Z"),
                "expires" : Date(9223372036854775000)
            }
        ]

我会这样做:

from pymongo import MongoClient, database, cursor, collection
client = MongoClient('localhost')
db = client['db1']
db.authenticate('user', 'pass', source='admin')
collection = db['collection']
for i in collection:
    # do something with i

并得到错误InvalidBSON: year 292278994 is out of range

有什么方法可以处理这个可笑的Date() 对象而不会使 bson 跌倒?我意识到在 Mongodb 中进行这样的约会很疯狂,但我对此无能为力,因为这不是我的数据。

【问题讨论】:

    标签: python mongodb mongodb-query pymongo


    【解决方案1】:

    我也遇到了同样的问题:

    正如尼尔提到的,我引用了:

    PyMongo 将 BSON 日期时间值解码为 Python 的 datetime.datetime 实例。 datetime.datetime 的实例是有限的

    所以仔细观察我的对象后,我注意到一些日期对象是这样的:0000:12:30T00:00:00

    就我而言,最好的方法是在将文档插入集合之前设置验证,因此如果日期为 0 ,将其设置为 1970 即可解决问题

    【讨论】:

      【解决方案2】:

      PyMongo 常见问题解答中实际上有一个关于这个主题的部分:

      Why do I get OverflowError decoding dates stored by another language’s driver?

      PyMongo 将 BSON 日期时间值解码为 Python 的 datetime.datetime 实例。 datetime.datetime 的实例仅限于 datetime.MINYEAR(通常为 1)和 datetime.MAXYEAR(通常为 9999)之间的年份。一些 MongoDB 驱动程序(例如 PHP 驱动程序)可以存储 BSON 日期时间,其年份值远远超出 datetime.datetime 支持的值。

      所以这里的基本约束是在 datetime.datetime 类型上,正如驱动程序为从 BSON 映射实现的那样,虽然它可能“荒谬”,但它对于其他语言来说是有效的,以创建这样的日期值。

      正如常见问题解答中指出的,您的一般解决方法是:

      1. 处理有问题的 BSON 日期。虽然存储是有效的,但它可能不是最初存储它的人/任何人的“真实”意图。

      2. 在您的代码中添加“日期范围”条件以过滤“超出范围”的日期:

        result = db['collection'].find({ 
          'expires': { '$gte': datetime.min, '$lte': datetime.max }
        })
        for i in result:
          # do something with i
        
      3. 如果您不需要进一步处理数据,请忽略投影中的违规日期字段:

        result = db['collection'].find({  }, projection={ 'expires': False })
        for i in result:
          # do something with i
        

      当然,'expires' 顾名思义,该值的最初意图是一个遥远的未来,它永远不会出现,该数据的原始作者(很可能当前代码仍在编写它) ) 不知道“Python”日期限制。因此,在所有文档以及任何代码仍在编写它的地方“降低”这个数字可能是相当安全的。

      【讨论】:

      • 谢谢。我还想出了一种方法,您可以通过调用 __getitem__ 函数来遍历结果并跳过任何返回 InvalidBSON 的结果。
      • @grinferno - 你有这个检查的例子吗?
      猜你喜欢
      • 1970-01-01
      • 2021-03-30
      • 2014-03-24
      • 2019-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多