Python+FastAPI中MongoDB日期范围过滤无结果问题排查
问题根源与解决方案
核心问题是D/M/Y格式的字符串无法正确按日期逻辑比较——MongoDB对字符串的比较是按字符顺序逐位判断的,而非实际日期的先后关系,这直接导致你的查询条件逻辑失效。
举个例子:集合中start_date为"15/03/2024",你传入的结束日期转成D/M/Y是"01/04/2024",字符串比较时"15/03/2024"会被判定为大于"01/04/2024"(因为第一个字符1比0大),但实际日期3月15日早于4月1日,这就导致符合条件的文档被错误过滤。
解决方法
方法1:查询时转换日期类型(无需修改现有数据)
使用MongoDB的$dateFromString操作符,将集合中的字符串日期转换为Date类型后再做比较,确保逻辑正确。示例代码如下:
from datetime import datetime from fastapi import FastAPI, Query import motor.motor_asyncio app = FastAPI() client = motor.motor_asyncio.AsyncIOMotorClient("mongodb://localhost:27017") db = client.your_database_name @app.get("/filter-items") async def filter_items(start: str = Query(...), end: str = Query(...)): # 转换传入的Y-M-D日期为datetime对象 input_start = datetime.strptime(start, "%Y-%m-%d") input_end = datetime.strptime(end, "%Y-%m-%d") # 构建带日期转换的查询条件 query = { "$expr": { "$and": [ {"$lte": [ {"$dateFromString": {"dateString": "$start_date", "format": "%d/%m/%Y"}}, input_end ]}, {"$gte": [ {"$dateFromString": {"dateString": "$final_date", "format": "%d/%m/%Y"}}, input_start ]} ] } } # 执行异步查询 cursor = db.your_collection.find(query) results = await cursor.to_list(length=None) return results
方法2:批量更新数据为Date类型(推荐长期方案)
如果数据量不大,建议直接将集合中的start_date和final_date字段从字符串改为Date类型,这样后续查询无需每次转换,性能更优。批量更新脚本示例:
async def batch_update_dates(): cursor = db.your_collection.find({"start_date": {"$type": "string"}}) async for doc in cursor: # 转换字符串日期为datetime对象 start_date = datetime.strptime(doc["start_date"], "%d/%m/%Y") final_date = datetime.strptime(doc["final_date"], "%d/%m/%Y") # 更新文档字段类型 await db.your_collection.update_one( {"_id": doc["_id"]}, {"$set": {"start_date": start_date, "final_date": final_date}} )
后续查询时,直接用datetime对象比较即可,无需额外转换:
query = { "start_date": {"$lte": input_end}, "final_date": {"$gte": input_start} }
内容的提问来源于stack exchange,提问作者Diego L
相关产品推荐
相关产品推荐

