You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步改造Telethon-MongoDB代码遇下标错误求助

解决Telethon+MongoDB异步改造中的两个常见错误

让我们一步步拆解你遇到的问题,然后给出可行的修复方案:

第一个错误:pymongo+asyncio的TypeError: 'coroutine' object is not subscriptable

你写的await loop.run_until_complete(a.finddb()[0])犯了两个关键问题:

  • 协程调用顺序错误:a.finddb()是一个协程对象,你先尝试对它做[0]下标操作,再传给run_until_complete,这就相当于直接去取协程对象的第0个元素,当然会报错。正确顺序是先等待协程执行完成,再对返回结果做下标操作。
  • pymongo本身不支持异步:pymongo是同步库,即使你用run_until_complete包裹,它的数据库操作还是会阻塞整个异步事件循环,违背异步编程的初衷,直接换Motor才是正确选择。

第二个错误:Motor的TypeError: 'AsyncIOMotorCursor' object is not subscriptable

Motor的find()方法返回的是AsyncIOMotorCursor异步游标,不是同步pymongo里的可迭代游标,更不是列表,所以不能直接用[0]取第一个元素。要获取游标里的文档,需要用异步方法消费:

  • 只需要第一个文档:用await cursor.next()(注意处理无结果的异常)
  • 需要多个文档:用await cursor.to_list(length=N)(N为要获取的数量,比如10)

另外还有几个优化点:

  • create_index不要放在每次查询的方法里,重复创建索引无意义,应该在程序启动时只执行一次。
  • Telethon代码里去掉sync导入,你用的是异步事件处理,sync是给同步代码用的,会干扰异步逻辑。

修正后的完整Motor版本代码

from telethon import TelegramClient, events, Button, utils
import re
import logging
import motor.motor_asyncio

# 提前初始化MongoDB客户端,避免每次创建Search实例都重新连接
myclient = motor.motor_asyncio.AsyncIOMotorClient(
    "mongodb+srv://login:pass@cluster0.ye4cx.mongodb.net/info?retryWrites=true&w=majority&ssl=true&ssl_cert_reqs=CERT_NONE"
)
mydb = myclient["info"]
mycol = mydb["comics"]

async def init_indexes():
    # 程序启动时创建一次索引,不要每次查询都创建
    await mycol.create_index([('title', 'text')], default_language='english')

class Search():
    def __init__(self, search):
        self.search = search
        # 直接使用全局的集合对象,避免重复创建客户端
        self.mycol = mycol

    async def searchdb(self):
        cursor = self.mycol.find({"$text": {"$search": self.search}})
        # Motor里count()是异步方法,必须await
        count = await cursor.count_documents()
        if count == 0:
            return []
        # 把游标转换成列表,这里取前10个结果
        return await cursor.to_list(length=10)

    async def finddb(self):
        cursor = self.mycol.find({"title": self.search})
        try:
            # 获取第一个文档,无结果时会抛出StopAsyncIteration
            return await cursor.next()
        except StopAsyncIteration:
            # 返回None表示未找到
            return None

# 假设你的bot已经完成初始化,示例:
# bot = TelegramClient('session_name', api_id, api_hash)

@bot.on(events.NewMessage(pattern=r'(?<=|).*(?=|)'))
async def find(event):
    search_text = event.text.replace("|", "")
    a = Search(search_text)
    find_result = await a.finddb()
    
    if not find_result:
        await event.respond("没有找到对应的漫画信息")
        return
    
    # 构造回复消息
    response = (
        f'**|{find_result.get("title")}|**\n\n'
        f'**Статус перевода**: {find_result.get("status")}\n'
        f'**Издатель**: {find_result.get("publisher")}\n\n'
        f'**Жанр**: {find_result.get("genres")}\n'
        f'**Описание**:\n{find_result.get("description")}'
    )
    await event.respond(response, buttons=[[Button.inline('Ссылки на скачку', b'next')]])

# 程序启动入口
async def main():
    await init_indexes()
    await bot.start()
    await bot.run_until_disconnected()

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

关键修复点说明

  1. 全局MongoDB客户端:避免重复创建数据库连接,提升性能。
  2. 异步索引初始化:仅在程序启动时创建一次文本索引,避免冗余操作。
  3. 正确消费Motor游标:用异步方法获取游标结果,适配Motor的异步特性。
  4. 错误处理:增加未找到文档时的友好回复,避免后续逻辑报错。
  5. 移除冗余导入:去掉Telethon的sync导入,符合异步编程规范。

内容的提问来源于stack exchange,提问作者fungalspores

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 15:37:54