迭代 PyMongo 游标抛出 InvalidBSON:年份超出范围

gri*_*rno 4 python mongodb pymongo mongodb-query

我正在使用 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)
            }
        ]
Run Code Online (Sandbox Code Playgroud)

我会做这样的事情:

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
Run Code Online (Sandbox Code Playgroud)

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

有什么办法可以在Date()不让 bson 摔倒的情况下处理这个可笑的对象吗?我意识到在 Mongodb 中有这样一个约会很疯狂,但我对此无能为力,因为它不是我的数据。

Nei*_*unn 6

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

为什么我会得到其他语言驱动程序存储的 OverflowError 解码日期?

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
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如果您不需要进一步处理数据,请忽略投影中的违规日期字段:

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

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

  • @grinferno - 你有这个检查的例子吗? (2认同)