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

如何在MongoDB服务层中使用async/await替代回调函数实现用户关联成就查询

问题描述

我正在基于MongoDB构建服务层,其中定义的User对象包含一个引用Achievements的数组。在完成用户身份验证后,我在服务层中编写了findForUser方法,通过回调函数查询指定用户关联的成就列表,代码如下:

findForUser(userId: string | Types.ObjectId): Promise<Achievement[]> {
  return new Promise((resolve) => {
    UserSchema.findOne({ _id: userId }, async (err: any, user: User) => {
      const AchievementMap: Achievement[] = [];
      if (err) throw new Error(err);
      user.achievements?.forEach((a) => {
        // @ts-ignore
        AchievementMap.push(a);
      });
      resolve(AchievementMap);
    });
  });
}

想请教如何用async/await替代当前的回调函数方式,实现返回UserSchema.findOne的查询结果?


解决方案

好问题!其实Mongoose的findOne方法本身就支持Promise接口,完全不需要手动包裹一层Promise再嵌套回调——用async/await可以让代码更简洁易读,同时错误处理也更规范。

改写步骤:

  1. 将方法标记为async:async方法会自动返回Promise,所以你不需要手动创建Promise实例
  2. 直接await findOne的结果:去掉回调参数,findOne在没有回调时会返回Promise,直接用await接收查询到的user对象
  3. 规范错误处理:用try/catch捕获查询过程中可能出现的错误,替代回调里的err判断
  4. 简化成就数组的提取:不需要手动遍历push到新数组,直接返回user.achievements(注意处理空值情况)

改写后的完整代码:

async findForUser(userId: string | Types.ObjectId): Promise<Achievement[]> {
  try {
    // 直接await findOne的Promise结果,不需要回调
    const user = await UserSchema.findOne({ _id: userId });
    
    // 处理用户不存在的情况(可选,但建议加上)
    if (!user) {
      throw new Error(`User with ID ${userId} not found`);
    }
    
    // 直接返回成就数组,空值时返回空数组避免undefined
    return user.achievements || [];
  } catch (err) {
    // 捕获并抛出错误,让上层调用者处理
    throw new Error(`Failed to fetch achievements: ${(err as Error).message}`);
  }
}

额外优化建议:

  • 如果不需要Mongoose的文档实例(比如不需要调用save等方法),可以在findOne后加.lean(),提升查询性能:
    const user = await UserSchema.findOne({ _id: userId }).lean();
    
  • 如果你确定user.achievements始终是数组(比如在Schema里设置了默认值为[]),可以直接返回user.achievements,不用加|| []

这样改写后,代码逻辑更清晰,错误处理也更符合async/await的最佳实践,同时避免了不必要的数组遍历和手动Promise包裹。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 05:47:35