使用gql-compose-mongoose如何在关联mongoose schema中互存ObjectID并实现关联查询
实现步骤
你需要分别完成双向关联数据写入、关联查询解析器注册两部分逻辑,具体实现如下:
1. 双向关联写入实现
创建挑战时使用MongoDB事务保证用户和挑战文档的关联字段同时更新,避免数据不一致:
import mongoose from "mongoose"; import { schemaComposer } from 'graphql-compose'; import { User, UserTC } from './userSchema.js'; import { Challenge, ChallengeTC } from './challengeSchema.js'; // 自定义创建挑战的Mutation schemaComposer.Mutation.addFields({ createChallengeBindUser: { type: ChallengeTC.getType(), args: { userId: "MongoID!", task: "String!", description: "String!" }, resolve: async (_, { userId, task, description }) => { const session = await mongoose.startSession(); session.startTransaction(); try { // 新建挑战,写入关联用户ID const [newChallenge] = await Challenge.create( [{ user: [userId], task, description }], { session } ); // 更新用户文档,写入关联挑战ID await User.findByIdAndUpdate( userId, { $push: { challenge: newChallenge._id } }, { session, new: true } ); await session.commitTransaction(); session.endSession(); return newChallenge; } catch (err) { await session.abortTransaction(); session.endSession(); throw new Error(`操作失败: ${err.message}`); } } } });
如果需要给已有挑战添加其他关联用户,可参照上述事务逻辑,新增对应Mutation即可。
2. 关联查询解析器注册
使用graphql-compose的addRelation方法注册关联字段,自动完成关联数据的populate查询:
// 给User类型添加查询关联挑战详情的字段 UserTC.addRelation('challengeList', { resolver: () => ChallengeTC.getResolver('findByIds'), prepareArgs: { _ids: (user) => user.challenge }, projection: { challenge: true } }); // 给Challenge类型添加查询关联用户详情的字段 ChallengeTC.addRelation('userList', { resolver: () => UserTC.getResolver('findByIds'), prepareArgs: { _ids: (challenge) => challenge.user }, projection: { user: true } });
3. 注册基础查询,生成Schema
schemaComposer.Query.addFields({ userById: UserTC.getResolver('findById'), challengeById: ChallengeTC.getResolver('findById') }); export const gqlSchema = schemaComposer.buildSchema();
4. GQL查询示例
查询指定用户的所有挑战详情
query GetUserChallenges($userId: MongoID!) { userById(_id: $userId) { _id name email challengeList { _id task description createdAt } } }
查询指定挑战关联的所有用户
query GetChallengeUsers($challengeId: MongoID!) { challengeById(_id: $challengeId) { _id task description userList { _id name email } } }
创建关联用户的挑战
mutation AddNewChallenge($userId: MongoID!, $task: String!, $desc: String!) { createChallengeBindUser(userId: $userId, task: $task, description: $desc) { _id task } }
内容的提问来源于stack exchange,提问作者Prabhat Mishra
相关产品推荐
相关产品推荐

