如何在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
相关产品推荐
相关产品推荐

