Subscription events trigger queries to be repeated unexpectedly when subscription returns same type of object but with subset of fields
See original GitHub issueWe have a query and related subscription that look like this:
const QUERY = qgl`
query CatQuery {
cat {
__typename
_id
qualities {
__typename
_id
cuddliness
}
}
}
`
const SUBSCRIPTION = qgl`
subscription CatSub {
catSub {
__typename
_id
qualities {
__typename
_id
}
}
}
`
i.e. the only difference between the fields requested from the query and subscription is that the subscription lacks qualities.cuddliness
. Both of these return objects with __typename
of Cat
.
Now we have two hooks happening in the same component:
useQuery(QUERY);
useSubscription(SUBSCRIPTION);
Now, every time the server sends a new update to the subscription, the query is sent again, which is completely redundant. 10 updates to the subscription = 10 queries sent to the server. With apollo client 2 this worked as we expected, subscription events would not cause new queries to be sent to the server.
If we remove cuddliness
from QUERY
(so that the query is no longer requesting a superset of the fields in the subscription) then this behavior goes away and we only ever get one query sent.
This is causing a lot of unnecessary queries to be sent from our client to our server since upgrading to apollo 3.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:4
- Comments:8 (2 by maintainers)
Top GitHub Comments
@cglacet Yep that’s exactly it, even when the subscription doesn’t add an element to the list, or even change the list in any way, the query still refetches.
If the subscription added a new element to the list with less fields than the query requires, it’s understandable. When the subscription doesn’t change the list in any way, the re-query is completely unnecessary.
@insidewhy Thanks for reporting issues as you attempt to update to Apollo Client 3, instead of suffering in silence!
In this case, you’ve hit on a common pitfall with list fields that are populated by multiple operations (queries/subscriptions/mutations), which can happen when one of the operations adds objects to the list that are missing some of the properties expected by other consumers of the list, leading to incomplete cache reads for those other consumers, leading to refetching in many cases (depending on
fetchPolicy
).I think the ultimate solution to this problem will involve some form of query transformation behind the scenes to ensure a given selection set includes all fields that might be needed by other consumers of that object. On a superficial level, this goes against the GraphQL principle of only fetching what you need, but I believe it would solve deeper problems, like this one.
In the meantime, you have a couple of workaround options:
...QualityFragment
for theCat.qualities
field in both theCatQuery
and theCatSub
, so thatcuddliness
is included in both places (or neither place).Quality.cuddliness
:This will ensure the
cuddliness
field never appears missing when reading from the cache, so its absence won’t trigger a refetch withfetchPolicy: "cache-first"
.