Apollo 奇怪地改变了查询结果
Apollo weirdly alters the query result
我在 React Native 中使用 react-apollo
s Query-Component 从我的后端获取数据。
结果看起来像这样:
[
{
id: 1,
name: 'US Election',
parties: [
{
name: 'democrats',
id: 4,
pivot: {
id: 3,
answers: [
{
id: 13,
question_id: 3,
reason: 'Lorem ipsum',
__typename: "Answer"
},
{
id: 14,
question_id: 5,
reason: 'Lorem ipsum',
__typename: "Answer"
},
],
__typename: "ElectionPartyPivot"
},
__typename: "Party"
},
],
__typename: "Election"
},
{
id: 2,
name: 'Another one',
parties: [
{
name: 'democrats',
id: 4,
pivot: {
id: 7,
answers: [
{
id: 15,
question_id: 7,
reason: 'Lorem ipsum',
__typename: "Answer"
},
{
id: 18,
question_id: 9,
reason: 'Lorem ipsum',
__typename: "Answer"
},
],
__typename: "ElectionPartyPivot"
},
__typename: "Party"
},
],
__typename: "Election"
}
]
现在,当我console.log
结果时,第二次选举"Another one"从第一个条目US Election
得到pivot
].
我认为这是因为 Apollo 内部正在进行规范化(因为双方的 ID 相同)但我不确定如何修复它,因此它不会规范化或规范化正确。
编辑
我想到了这个解决方案,但它看起来很老套。我现在将 election_id 与聚会一起获取,并在缓存中创建一个不同的标识符。我想知道这是否是好的做法?
const cache = new InMemoryCache({
dataIdFromObject: object => {
switch (object.__typename) {
case 'Party': return `${object.election_id}:${object.id}`;
default: return defaultDataIdFromObject(object);
}
}
});
const client = new ApolloClient({
uri: config.apiUrl,
cache
});
是的,在这种情况下提供自定义 dataIdFromObject
是必要的。您应该考虑使用 Party:${object.election_id}:${object.id}
作为键,以防将来有其他 Election
字段需要相同的处理。
从根本上说,这是架构设计方式的问题。 GraphQL 中有一个潜在的假设,即虽然 GraphQL 中的节点可能彼此有关系,但它们也完全相互独立。也就是说,在同一个上下文中,同一个节点不应根据响应中其他节点的存在与否来代表不同的数据。
不幸的是,这正是这个响应的结构——我们有一个代表 Party
的节点,但它的字段根据它与另一个节点的关系而不同——Election
。
有两种方法可以解决此类问题。一种方法是维护每个 Party
的不同实例,每个 Election
具有不同的 ID。 Party
类型背后的基础数据模型不会代表一个政党的整个生命周期,而是只会在一次选举的背景下呈现一个政党。
另一种方法是重构您的模式以更准确地表示节点之间的关系。例如,支持这种查询的架构:
{
elections {
id
name
parties {
id
name
# omit pivot field on Party type
}
# instead because pivots are related directly to elections, add this field
pivots {
id
answers
# because we may still care what party the pivot is associated with as well
# we can add a party field to pivot to show that relationship
party {
id
name
}
}
}
}
我在 React Native 中使用 react-apollo
s Query-Component 从我的后端获取数据。
结果看起来像这样:
[
{
id: 1,
name: 'US Election',
parties: [
{
name: 'democrats',
id: 4,
pivot: {
id: 3,
answers: [
{
id: 13,
question_id: 3,
reason: 'Lorem ipsum',
__typename: "Answer"
},
{
id: 14,
question_id: 5,
reason: 'Lorem ipsum',
__typename: "Answer"
},
],
__typename: "ElectionPartyPivot"
},
__typename: "Party"
},
],
__typename: "Election"
},
{
id: 2,
name: 'Another one',
parties: [
{
name: 'democrats',
id: 4,
pivot: {
id: 7,
answers: [
{
id: 15,
question_id: 7,
reason: 'Lorem ipsum',
__typename: "Answer"
},
{
id: 18,
question_id: 9,
reason: 'Lorem ipsum',
__typename: "Answer"
},
],
__typename: "ElectionPartyPivot"
},
__typename: "Party"
},
],
__typename: "Election"
}
]
现在,当我console.log
结果时,第二次选举"Another one"从第一个条目US Election
得到pivot
].
我认为这是因为 Apollo 内部正在进行规范化(因为双方的 ID 相同)但我不确定如何修复它,因此它不会规范化或规范化正确。
编辑
我想到了这个解决方案,但它看起来很老套。我现在将 election_id 与聚会一起获取,并在缓存中创建一个不同的标识符。我想知道这是否是好的做法?
const cache = new InMemoryCache({
dataIdFromObject: object => {
switch (object.__typename) {
case 'Party': return `${object.election_id}:${object.id}`;
default: return defaultDataIdFromObject(object);
}
}
});
const client = new ApolloClient({
uri: config.apiUrl,
cache
});
是的,在这种情况下提供自定义 dataIdFromObject
是必要的。您应该考虑使用 Party:${object.election_id}:${object.id}
作为键,以防将来有其他 Election
字段需要相同的处理。
从根本上说,这是架构设计方式的问题。 GraphQL 中有一个潜在的假设,即虽然 GraphQL 中的节点可能彼此有关系,但它们也完全相互独立。也就是说,在同一个上下文中,同一个节点不应根据响应中其他节点的存在与否来代表不同的数据。
不幸的是,这正是这个响应的结构——我们有一个代表 Party
的节点,但它的字段根据它与另一个节点的关系而不同——Election
。
有两种方法可以解决此类问题。一种方法是维护每个 Party
的不同实例,每个 Election
具有不同的 ID。 Party
类型背后的基础数据模型不会代表一个政党的整个生命周期,而是只会在一次选举的背景下呈现一个政党。
另一种方法是重构您的模式以更准确地表示节点之间的关系。例如,支持这种查询的架构:
{
elections {
id
name
parties {
id
name
# omit pivot field on Party type
}
# instead because pivots are related directly to elections, add this field
pivots {
id
answers
# because we may still care what party the pivot is associated with as well
# we can add a party field to pivot to show that relationship
party {
id
name
}
}
}
}