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

如何在Nest与Mercurius中启用Redis缓存和Loaders

在Nest + Mercurius中启用GraphQL缓存与Data Loaders

我正在用Nest和Mercurius构建GraphQL API,已经实现了基础的查询和解析器,现在想通过启用Loaders和缓存来提升性能。但Nest官方文档里关于GraphQL的这部分配置说明不够明确,我也不知道怎么在Nest里正确配置mercurius-cache和Loaders。

以下是我的代码:

app.module.ts

import { MercuriusDriver, MercuriusDriverConfig } from '@nestjs/mercurius';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ProjectsModule } from './projects/projects.module';

@Module({
  imports: [
    ProjectsModule,
    GraphQLModule.forRoot<MercuriusDriverConfig>({
      driver: MercuriusDriver,
      autoSchemaFile: 'schema.gql',
      subscription: true,
      graphiql: true,
    }),
  ],
})
export class AppModule {}

ProjectsResolver.ts

import { Args, Query, Resolver } from '@nestjs/graphql';
import { Project } from './models/project.model';
import { ProjectsService } from './projects.service';

@Resolver(of => Project)
export class ProjectsResolver {
    constructor(
        private projectsService: ProjectsService, // 注:原代码笔误为authorsService,已修正
    ) {}

    @Query(returns => Project)
    async project(@Args('id') id: number) {
        return this.projectsService.findOneById(id);
    }
}

解决方案

一、启用mercurius-cache

首先安装依赖:

npm install mercurius-cache

在GraphQLModule.forRoot配置中添加插件注册缓存:

import { MercuriusDriver, MercuriusDriverConfig } from '@nestjs/mercurius';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ProjectsModule } from './projects/projects.module';
import { cache } from 'mercurius-cache';

@Module({
  imports: [
    ProjectsModule,
    GraphQLModule.forRoot<MercuriusDriverConfig>({
      driver: MercuriusDriver,
      autoSchemaFile: 'schema.gql',
      subscription: true,
      graphiql: true,
      // 配置缓存插件
      plugins: [
        cache({
          ttl: 60, // 全局缓存过期时间(秒)
          storage: { type: 'memory' }, // 内存存储,也可替换为Redis
          policy: {
            Query: {
              // 配置需要缓存的查询
              project: {
                ttl: 120, // 单独设置该查询的过期时间
                key: (args) => `project:${args.id}`, // 用ID作为缓存键
              },
            },
          },
        }),
      ],
    }),
  ],
})
export class AppModule {}

二、启用Data Loaders(解决N+1查询问题)

1. 创建Project Loader

在projects模块下新建project.loader.ts:

import { Injectable } from '@nestjs/common';
import { DataLoader } from '@nestjs/graphql';
import { ProjectsService } from './projects.service';

@Injectable()
export class ProjectLoader implements DataLoader<number, any> {
  constructor(private readonly projectsService: ProjectsService) {}

  // 实现批量加载逻辑
  async loadMany(ids: readonly number[]) {
    const projects = await this.projectsService.findManyByIds(ids);
    // 保证返回顺序与传入的ID数组一致
    return ids.map(id => projects.find(project => project.id === id));
  }
}

2. 注册Loader到模块

修改projects.module.ts,将Loader加入 providers:

import { Module } from '@nestjs/common';
import { ProjectsResolver } from './projects.resolver';
import { ProjectsService } from './projects.service';
import { ProjectLoader } from './project.loader';

@Module({
  providers: [ProjectsResolver, ProjectsService, ProjectLoader],
})
export class ProjectsModule {}

3. 在解析器中使用Loader

修改ProjectsResolver注入并使用Loader:

import { Args, Query, Resolver, Loader } from '@nestjs/graphql';
import { Project } from './models/project.model';
import { ProjectsService } from './projects.service';
import { ProjectLoader } from './project.loader';
import { DataLoader } from '@nestjs/graphql';

@Resolver(of => Project)
export class ProjectsResolver {
    constructor(
        private projectsService: ProjectsService,
        @Loader(ProjectLoader) private readonly projectLoader: DataLoader<number, Project>,
    ) {}

    @Query(returns => Project)
    async project(@Args('id') id: number) {
        // 使用Loader加载数据,自动处理批量与缓存
        return this.projectLoader.load(id);
    }

    // 新增批量查询示例
    @Query(returns => [Project])
    async projects(@Args('ids', { type: () => [Number] }) ids: number[]) {
        return this.projectLoader.loadMany(ids);
    }
}

4. 实现Service的批量查询方法

在ProjectsService中添加批量查询逻辑:

import { Injectable } from '@nestjs/common';

@Injectable()
export class ProjectsService {
  // 模拟数据库数据
  private projects = [
    { id: 1, name: 'Project A' },
    { id: 2, name: 'Project B' },
  ];

  async findOneById(id: number) {
    return this.projects.find(p => p.id === id);
  }

  // 新增批量查询方法
  async findManyByIds(ids: number[]) {
    return this.projects.filter(p => ids.includes(p.id));
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 15:25:28