question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Subscription events trigger queries to be repeated unexpectedly when subscription returns same type of object but with subset of fields

See original GitHub issue

We 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:open
  • Created 2 years ago
  • Reactions:4
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
insidewhycommented, May 11, 2021

@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.

1reaction
benjamncommented, May 4, 2021

@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:

  1. Use a shared ...QualityFragment for the Cat.qualities field in both the CatQuery and the CatSub, so that cuddliness is included in both places (or neither place).
  2. Use a field policy to define a default value for Quality.cuddliness:
new InMemoryCache({
  typePolicies: {
    Quality: {
      fields: {
        cuddliness(existing = "not cuddly") {
          return existing;
        },
      },
    },
  },
})

This will ensure the cuddliness field never appears missing when reading from the cache, so its absence won’t trigger a refetch with fetchPolicy: "cache-first".

Read more comments on GitHub >

github_iconTop Results From Across the Web

Subscriptions - Apollo GraphQL Docs
Small, incremental changes to large objects. Repeatedly polling for a large object is expensive, especially when most of the object's fields rarely change....
Read more >
Trigger after insert/after update - Salesforce Developers
Hi am facing below Error. Logic needs to be implemented :If type is Contract Flow and Document Attached is True then HandOffAttached =True, ......
Read more >
Schema reference for trigger and action types - Azure Logic ...
This trigger sends a subscription request to an endpoint by using a Microsoft-managed API, provides a callback URL to where the endpoint can ......
Read more >
Angular/RxJS When should I unsubscribe from `Subscription`
TL;DR. For this question there are two kinds of Observables - finite value and infinite value. http Observables produce finite (1) values and...
Read more >
Cloud Firestore triggers | Cloud Functions for Firebase
On this page · Cloud Firestore function triggers · Writing Cloud Firestore-triggered functions. Define a function trigger; Specify a single document · Event...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found