我试图查询一个MongoDB文档(trivia
)使用GraphQL(Apollo Server),但其中一个文档字段有问题。
LightningRoundQuestion.answer
和 PictureRoundPicture.answer
应返回 String
和 MultipleChoiceRoundQuestion.answer
应该返回一个 Int
. 参见模式。
schema
const typeDefs = gql`
# ROOT TYPES ==================================================
type Query {
trivia(_id: String!): Trivia
}
# INTERFACES ==================================================
interface Round {
type: String!
theme: String!
pointValue: Int!
}
type LightningRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [LightningRoundQuestion]
}
type MultipleChoiceRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [MultipleChoiceRoundQuestion]
}
type PictureRound implements Round {
type: String!
theme: String!
pointValue: Int!
pictures: [PictureRoundPicture]
}
# QUERY TYPES =================================================
type LightningRoundQuestion {
question: String!
answer: String!
}
type MultipleChoiceRoundQuestion {
question: String!
options: [String!]!
answer: Int!
}
type PictureRoundPicture {
url: String!
answer: String!
}
type Trivia {
_id: String!
createdAt: String!
triviaId: String!
triviaPin: String!
host: String!
rounds: [Round]!
tieBreaker: TieBreaker!
}
type TieBreaker {
question: String
answer: Int
}
`
resolvers & server
const resolvers = {
Query: {
trivia: async (root, { _id }) => {
return triviaCollection.findOne(ObjectId(_id))
}
},
Round: {
__resolveType(obj) {
if (obj.type === 'multipleChoice') {
return 'MultipleChoiceRound'
} else if (obj.type === 'lightning') {
return 'LightningRound'
} else if (obj.type === 'picture') {
return 'PictureRound'
}
}
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`)
})
query
query {
trivia(_id: "5e827a4e1c9d4400009fea32") {
_id
createdAt
triviaId
triviaPin
host
rounds {
... on LightningRound {
questions {
question
answer
}
}
... on MultipleChoiceRound {
questions {
question
options
answer
}
}
... on PictureRound {
pictures {
url
answer
}
}
}
}
}
我得到了错误信息。
"message": "Fields \"questions\" conflict because subfields \"answer\" conflict because they return conflicting types \"String!\" and \"Int!\". Use different aliases on the fields to fetch both if this was intentional."
我不太确定下一步该怎么做,我看了一下: 阿波罗文件中的别名,但那里没有什么帮助。
当使用抽象类型时,这是个小问题,是GraphQL处理合并字段选择的结果。归结起来就是,如果你在同一个选择集中多次请求一个具有相同名称(或别名)的字段,该字段必须返回相同的类型。在上面的模式中,它不需要 -- 问题可以有相同的类型。[LightningRoundQuestion]
或 [PictureRoundPicture]
等等。
详细的解释,请看 本节 的规范。
有两个变通的方法。在客户端,你可以使用别名来确保GraphQL不会首先尝试合并字段。
rounds {
... on LightningRound {
lightningQuestions: questions {
question
answer
}
}
... on MultipleChoiceRound {
multipleChoiceQuestions: questions {
question
options
answer
}
}
}
当你不能改变模式时,这是你最好的选择。然而,你也可以在服务器端改变字段的名称,以获得更好的客户端DX。
rounds {
... on LightningRound {
lightningQuestions {
question
answer
}
}
... on MultipleChoiceRound {
multipleChoiceQuestions {
question
options
answer
}
}
}
请注意,我们不需要对以下情况进行处理。type
, theme
或 pointValue
因为这些字段在你所有的实现类型中具有相同的类型。