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

Apollo Server Express v4中this.findOneById不是函数问题排查

Apollo Server v4 中 apollo-datasource-mongodb 方法调用失败问题解决

问题场景

使用 Apollo Server v4 时,编写了如下基于 apollo-datasource-mongodb 的数据源代码:

import { MongoDataSource } from 'apollo-datasource-mongodb'

export default class LoaderAsset extends MongoDataSource {
 async getAsset(assetId) {
    return this.findOneById(assetId) // 错误发生在此处
  }
}

async function startApolloServer(app) {
  const httpServer = http.createServer(app);
  
  const server = new ApolloServer({
    typeDefs,
    resolvers,
    plugins: [ApolloServerPluginDrainHttpServer({ httpServer })]
    
  });

  await server.start();
  app.use(
    '/graphql',
    cors(),
    bodyParser.json(),
    expressMiddleware(server, {
      context: async ({ req }) => {
       return {
        dataSources: {
          loaderAsset: new LoaderAsset(modelAsset),
        }
      }
      },
    }),
  );


  const port = config.get('Port') || 8081;
  await new Promise(resolve => httpServer.listen({ port }, resolve));
}

调用 getAsset 时出现错误:

this.findOneById is not a function
另外,this包含collection和model对象,但没有任何方法。

用户疑问:是否是 apollo-datasource-mongodb 与 Apollo Server v4 不兼容?v3 中 dataSources 是独立配置项,v4 放在 context 中是否是问题根源?

问题原因

是的,问题根源就是 Apollo Server v4 的架构变更与 apollo-datasource-mongodb 的兼容性冲突。Apollo Server v3 会自动对配置的数据源进行初始化:调用数据源的 initialize 方法,绑定正确的 this 上下文,并注入相关方法;但 v4 移除了专门的 dataSources 配置项,要求开发者在 context 中手动实例化数据源,这跳过了 apollo-datasource-mongodb 依赖的初始化流程,导致 LoaderAsset 实例仅拥有传入的 collection/model 属性,却没有继承自 MongoDataSource 的方法。

解决办法

方案1:手动封装数据源(推荐)

放弃依赖 apollo-datasource-mongodb,直接基于 MongoDB/Mongoose 原生方法封装数据源,适配 v4 架构:

export default class LoaderAsset {
  constructor(model) {
    this.model = model;
  }

  async getAsset(assetId) {
    // 直接使用 Mongoose 的 findById 方法,或 MongoDB 原生的 findOne({_id: assetId})
    return this.model.findById(assetId);
  }
}

这种方式无兼容性风险,更贴合 v4 的设计思路。

方案2:手动触发数据源初始化(临时方案)

若必须使用 apollo-datasource-mongodb,可手动调用其 initialize 方法模拟 v3 的初始化流程:

context: async ({ req }) => {
  const loaderAsset = new LoaderAsset(modelAsset);
  // 手动执行初始化,绑定上下文
  await loaderAsset.initialize({
    context: { req }, // 传入当前请求上下文
    dataSources: {}, // 若有其他数据源可传入
  });
  return {
    dataSources: {
      loaderAsset,
    }
  }
},

注意:此方法属于临时 hack,后续版本可能出现新的兼容问题,不推荐长期使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 21:10:36