GraphQL/Graphcool:如何编写关联一对一与一对多关系的Mutation
修改Mutation以关联Show与Venue、Artists
嘿,我来帮你搞定这个Show关联Venue和Artists的问题!首先得明确,要建立这种关联,咱们得从GraphQL的类型定义和Mutation的 resolver 逻辑两方面入手,下面一步步拆解:
1. 先确认并完善GraphQL类型定义
首先要保证你的Show类型已经包含了关联Venue和Artists的字段,这样返回的结果才能带出关联数据。示例类型定义如下:
type Show { id: ID! # 这里是你showInfo里的原有字段,比如date、time、ticketPrice等 date: String! time: String! ticketPrice: Float! # 关联字段:指向对应的Venue和Artist列表 venue: Venue! artists: [Artist!]! } type Mutation { # 保持入参:venueId、artistIds、showInfo createShow(venueId: ID!, artistIds: [ID!]!, showInfo: ShowInfoInput!): Show! } # 你的showInfo输入类型,保持原有字段即可 input ShowInfoInput { date: String! time: String! ticketPrice: Float! }
2. 修改Mutation的Resolver核心逻辑
接下来就是关键的resolver部分,要在创建Show的同时,完成和Venue、Artists的关联。不同数据库的实现略有差异,我给你两种常见场景的示例:
场景一:SQL数据库(比如PostgreSQL + Sequelize ORM)
如果用SQL,Show和Venue是一对多关系(一个Venue对应多个Show),Show和Artists是多对多关系(一个Show有多个艺人,一个艺人可以参与多个Show),需要中间表来维护多对多关联:
const resolvers = { Mutation: { createShow: async (parent, { venueId, artistIds, showInfo }, context) => { // 第一步:验证Venue和Artists是否存在(*可选但推荐*,避免无效ID导致的脏数据) const existingVenue = await context.models.Venue.findByPk(venueId); if (!existingVenue) { throw new Error(`ID为${venueId}的场地不存在`); } const existingArtists = await context.models.Artist.findAll({ where: { id: artistIds } }); if (existingArtists.length !== artistIds.length) { throw new Error("部分艺人ID无效,请检查"); } // 第二步:创建Show,关联Venue(通过外键venueId) const show = await context.models.Show.create({ ...showInfo, venueId // 将venueId作为外键存入Show表 }); // 第三步:关联Show和Artists(Sequelize的addArtists方法会自动操作中间表) await show.addArtists(existingArtists); // 返回创建后的Show,后续通过Show类型的resolver获取关联数据 return show; } }, // 补充Show类型的resolver,确保能正确返回关联的Venue和Artists Show: { venue: (parent) => parent.getVenue(), artists: (parent) => parent.getArtists() } };
场景二:MongoDB(Mongoose)
MongoDB是文档型数据库,通常用引用ID来维护关联:
const resolvers = { Mutation: { createShow: async (parent, { venueId, artistIds, showInfo }, context) => { // 验证存在性 const venueExists = await context.models.Venue.exists({ _id: venueId }); if (!venueExists) { throw new Error(`ID为${venueId}的场地不存在`); } const validArtistCount = await context.models.Artist.countDocuments({ _id: { $in: artistIds } }); if (validArtistCount !== artistIds.length) { throw new Error("部分艺人ID无效,请检查"); } // 创建Show文档,直接存储Venue和Artists的ID引用 const show = new context.models.Show({ ...showInfo, venue: venueId, // 存储Venue的ObjectId artists: artistIds // 存储Artist的ObjectId数组 }); await show.save(); // 可选:如果需要返回完整的Venue和Artists数据,用populate方法填充 await show.populate('venue').populate('artists'); return show; } } };
3. 调用修改后的Mutation示例
修改完成后,你可以这样调用Mutation来获取包含关联数据的结果:
mutation { createShow( venueId: "V123" artistIds: ["A456", "A789"] showInfo: { date: "2024-10-01" time: "20:00" ticketPrice: 50.00 } ) { id date time venue { id name address } artists { id name genre } } }
内容的提问来源于stack exchange,提问作者fox
相关产品推荐
相关产品推荐

