PyMongo日期查询在Kubernetes集群无结果但本地正常的问题
我用Python 3.12.4编写代码,通过Docker容器部署的MongoDB(镜像为dockerhub的mongo:4.4.7)插入JSON数据,代码如下:
myClient = pymongo.MongoClient("mongodb://%s:%s@%s" % (MONGO_USER, MONGO_PASS, MONGO_CONN), timeoutMS=10000) myDB = myClient[CLIENT_NAME] myCollection = myDB[COLLECTION_NAME] the_json = '{"id": "json1","thedate": "2020-05-11T12:22:34.876Z"}' myRecord = json.loads(the_json) # replace str date with python' datetime object myRecord["thedate"] = datetime.strptime(myRecord["thedate"], "%Y-%m-%dT%H:%M:%S.%fZ") insertionResult = myCollection.insert_one(myRecord) startDate = datetime(2020, 8, 12, 4, 21, 3, 923453) mySearch = myCollection.find({"thedate": {"$gt": startDate}})
上述代码在本地环境中能正确返回查询结果。但将相同代码、相同MongoDB镜像及Python库部署到Kubernetes集群后,执行带日期条件的查询无结果返回,不过执行myCollection.find()能获取所有记录,说明不存在连接问题。
我尝试了多种日期类型用于查询,包括:
startDate = datetime(2012, 11, 2, 11, 10, 13, 123123, pytz.UTC) startDate = datetime.now(tz=pytz.utc)- timedelta(days=7) startDate = datetime(2013, 3, 12, 6, 54, 4, 123123) startDate = datetime.now() - timedelta(days=4)
以下是各容器的时间信息:
MY PC DATE: lun 21 oct 2024 18:27:08 CEST+0200 DATE MONGODB RUN IN DOCKERS LOCALLY: Mon Oct 21 16:26:43 UTC 2024 +0000 DATE MONGODB RUN IN KUBERNETES: Mon Oct 21 16:29:24 UTC 2024 +0000 DATE PYTHON CODE KUBERNETES: Mon Oct 21 16:30:44 UTC 2024 +0000
通过Mongo CLI检查存储的日期类型为ISODate,显示正常:
> date_obj = db["collection-name"].findOne({ thestr: 'exampleFile' }).thedate ISODate("2024-10-15T11:59:59.111Z") > date_obj.toString() Tue Oct 15 2024 11:59:59 GMT+0000 (UTC)
请问可能是什么原因导致该问题?为何本地正常但Kubernetes集群中异常?
核心诱因:时区处理逻辑不一致
本地环境与K8s环境的时区差异,加上pymongo对带时区datetime对象和无时区naive datetime对象的处理逻辑差异,是最可能的问题根源。
1. 强制插入和查询的datetime带UTC时区
MongoDB存储的ISODate本质是UTC时区的时间戳,若代码中使用无时区的naive datetime,pymongo会根据运行环境的系统时区自动转换——本地环境是CEST+0200,K8s环境是UTC,转换结果差异会导致查询对比逻辑反转。
修正代码:
from datetime import datetime import pytz import json import pymongo # 插入时,将字符串转成带UTC时区的datetime myRecord["thedate"] = datetime.strptime(myRecord["thedate"], "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=pytz.UTC) # 查询时,同样使用带UTC时区的startDate startDate = datetime(2020, 8, 12, 4, 21, 3, 923453, tzinfo=pytz.UTC) mySearch = myCollection.find({"thedate": {"$gt": startDate}})
2. 确保pymongo版本完全一致
即使你声称使用相同的Python库,本地与K8s环境的pymongo版本可能存在细微差异。MongoDB 4.4.7与高版本pymongo(如4.6+)的datetime处理逻辑有变化,比如对naive datetime的默认时区假设从本地时区改为UTC,导致查询结果异常。
解决方法:在requirements.txt中固定pymongo版本,比如:
pymongo==4.5.0 # 替换为你本地环境的实际版本
3. 验证插入数据的时区正确性
通过Mongo CLI查看数据的原始BSON结构,确认K8s环境中插入的日期确实是UTC时区的ISODate:
db["collection-name"].findOne({}, {thedate: 1, _id: 0})
如果返回的ISODate与预期不符,说明插入时的datetime转换逻辑在K8s环境中存在问题,需要重新确认代码中的时区处理。
4. 排查索引问题(次要)
虽然索引缺失不会导致查询无结果,但可能影响查询性能或出现意外的排序问题。检查集合是否存在thedate字段的索引:
db["collection-name"].getIndexes()
如果缺少,创建索引:
db["collection-name"].createIndex({thedate: 1})
内容的提问来源于stack exchange,提问作者user27918202

