Django中如何将MongoDB Motor的MotorLatentCommandCursor转为列表
Motor LatentCommandCursor 转列表的正确实现
报错根因
MotorLatentCommandCursor是Motor驱动返回的异步类型游标,仅支持异步协议消费,不支持同步操作读取。
此前代码中await list(documents)的写法存在两处逻辑错误:
list()是Python内置的同步方法,无法消费异步游标对象,调用时不会触发数据库查询拉取逻辑- 同步方法被错误套上
await语法后,会阻塞异步事件循环,最终在事件轮询阶段抛出select相关的异常
官方推荐实现方案
1. 调用游标原生to_list()异步方法
Motor游标内置了异步的to_list()方法,是批量拉取游标数据转列表的标准实现:
# 执行聚合操作拿到游标 cursor = db.factor.aggregate([ {"$limit": 3}, {"$lookup": { "from": "subfactor", "localField": "_id", "foreignField": "factor_id", "as": "subfactor" }} ]) # 直接await调用to_list方法完成转换 # length参数设为None代表拉取全部匹配数据 documents = await cursor.to_list(length=None) for d in documents: print(d)
注意:如果聚合返回的数据量较大,建议给length传入合理的阈值,避免一次性拉取过多数据占用过高内存。
2. 通过异步遍历手动构建列表
也可以利用Python的异步迭代语法async for逐行读取游标数据,手动拼装为列表,适配自定义加工逻辑的场景:
documents = [] async for doc in cursor: # 可在此处对单条文档做自定义加工 documents.append(doc)
常见踩坑提示
- 禁止使用同步
for...in、内置list()函数直接操作Motor游标,这类同步逻辑没有异步IO调度介入,会直接卡死事件循环 - 在Django项目中使用时,需确保调用Motor异步接口的链路在异步上下文(异步视图、异步任务)中运行,同步视图内直接写await逻辑同样会触发事件循环阻塞问题
内容的提问来源于stack exchange,提问作者Amirhossein Azhdari
相关产品推荐
相关产品推荐

