TypeGraphQL与MongoDB:使用Mongoose构建NoSQL GraphQL服务
【免费下载链接】type-graphql 项目地址: https://gitcode.com/gh_mirrors/typ/type-graphql
TypeGraphQL与MongoDB的组合为构建灵活的NoSQL GraphQL服务提供了强大支持。本教程将通过examples/typegoose/示例项目,展示如何使用Mongoose(通过Typegoose)实现数据建模、关系处理和GraphQL API开发。
技术架构概览
TypeGraphQL负责类型定义和 resolver 实现,MongoDB提供文档存储,Typegoose作为桥梁连接两者。核心组件包括:
- 实体建模:使用TypeGraphQL装饰器定义GraphQL类型,同时通过Typegoose装饰器映射MongoDB集合
- 中间件转换:处理Mongoose文档到TypeGraphQL对象的转换
- 自定义标量:实现MongoDB ObjectId与GraphQL类型的映射
环境配置与依赖
项目基础配置位于examples/typegoose/index.ts,关键依赖包括:
import { buildSchema } from "type-graphql";
import { connect } from "mongoose";
import { TypegooseMiddleware } from "./typegoose.middleware";
import { ObjectIdScalar } from "./object-id.scalar";
启动流程包含MongoDB连接、数据库初始化和GraphQL服务器启动:
// 创建数据库连接
const mongoose = await connect(process.env.DATABASE_URL!);
// 构建GraphQL schema
const schema = await buildSchema({
resolvers: [RecipeResolver, RatingResolver],
globalMiddlewares: [TypegooseMiddleware],
scalarsMap: [{ type: Types.ObjectId, scalar: ObjectIdScalar }],
});
数据模型设计
实体定义
实体类同时标注GraphQL类型和MongoDB集合结构,以examples/typegoose/entities/recipe.ts为例:
@ObjectType()
export class Recipe {
@Field()
readonly id!: Types.ObjectId;
@Field()
@Property({ required: true })
title!: string;
@Field(_type => User)
@Property({ ref: User, required: true })
author!: Ref<User>;
}
export const RecipeModel = getModelForClass(Recipe);
自定义ObjectId标量
MongoDB的ObjectId类型需要自定义GraphQL标量处理,实现位于examples/typegoose/object-id.scalar.ts:
export const ObjectIdScalar = new GraphQLScalarType({
name: "ObjectId",
description: "Mongo object id scalar type",
serialize(value: unknown): string {
if (!(value instanceof Types.ObjectId)) {
throw new Error("ObjectIdScalar can only serialize ObjectId values");
}
return value.toHexString();
},
// 省略parseValue和parseLiteral实现
});
文档转换中间件
Mongoose文档需要转换为普通对象才能被GraphQL正确序列化,中间件实现见examples/typegoose/typegoose.middleware.ts:
export const TypegooseMiddleware: MiddlewareFn = async (_, next) => {
const result = await next();
if (Array.isArray(result)) {
return result.map(item => (item instanceof Model ? convertDocument(item) : item));
}
if (result instanceof Model) {
return convertDocument(result);
}
return result;
};
Resolver实现
Resolver处理GraphQL查询和变更,以examples/typegoose/resolvers/recipe.resolver.ts为例:
查询操作
@Query(_returns => Recipe, { nullable: true })
recipe(@Arg("recipeId", () => ObjectIdScalar) recipeId: Types.ObjectId) {
return RecipeModel.findById(recipeId);
}
@Query(_returns => [Recipe])
async recipes(): Promise<Recipe[]> {
return RecipeModel.find({});
}
变更操作
@Mutation(_returns => Recipe)
async addRecipe(
@Arg("recipe") recipeInput: RecipeInput,
@Ctx() { user }: Context,
): Promise<Recipe> {
const recipe = new RecipeModel({
...recipeInput,
author: user.id,
});
await recipe.save();
return recipe;
}
字段解析器
处理关联数据加载:
@FieldResolver()
async author(@Root() recipe: Recipe): Promise<User> {
return (await UserModel.findById(recipe.author))!;
}
实际查询示例
examples/typegoose/examples.graphql提供了完整的查询示例:
query GetRecipe {
recipe(recipeId: "64551384aac388414b391778") {
_id
title
ratings {
value
user {
nickname
}
}
author {
nickname
email
}
}
}
项目结构与扩展
完整项目结构可参考examples/typegoose/目录,主要包括:
- entities/: 数据模型定义
- resolvers/: GraphQL解析器
- types/: 输入输出类型定义
- helpers.ts: 数据库初始化工具
通过这种架构,开发者可以快速构建类型安全、关系清晰的GraphQL服务,同时充分利用MongoDB的文档模型优势。
【免费下载链接】type-graphql 项目地址: https://gitcode.com/gh_mirrors/typ/type-graphql
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考





