Apollo-client: Updating cached data from multiple parameterized queries after a mutation

Created on 12 Feb 2018  Â·  10Comments  Â·  Source: apollographql/apollo-client

Appears that the 2 related issues https://github.com/apollographql/react-apollo/issues/708 and https://github.com/apollographql/apollo-client/issues/1697 were closed without an efficient solution - so re-opening here as I am having the same issue.

The crux of the problem is this:

  1. I have a mutation that creates/deletes nodes.
  2. I have multiple co-located, parameterized queries that need to re-run when a create/delete mutation happens.
  3. Updating the store manually inside update is non-trivial given that all co-located and parameterized queries that were affected by the create/delete mutation need to be re-run.
  4. The variables applied to each parameterized query are applied dynamically and are not easily discoverable or in scope at the update call site.

Interested to hear thoughts from the apollo team on an update pattern that fits here.

Thanks!

Most helpful comment

@SachaG I was able to solve the mentioned problem of not knowing which arguments to use for a cached query here:
https://www.apollographql.com/docs/react/advanced/caching.html#connection-directive
so, essentially, if the query has @connection directive in it, in the cache it'll be stored without extra arguments.

All 10 comments

It appears that refetchQueries already provides this functionality...

From the docs...
https://www.apollographql.com/docs/react/basics/mutations.html#graphql-mutation-options-refetchQueries

If options.refetchQueries is an array of strings then Apollo Client will look for any queries with the same names as the provided strings and will refetch those queries with their current variables.

This actually solves my current problem as I simply needed a way to re-run queries by name without needing to know what arguments were applied to the query, as they may differ throughout the application.

If I have a query
allJobsByOwner($ownerId:ID!)

every time the query is run apollo will create a new key under ROOT_QUERY..

ROOT_QUERY:
    allJobsByOwner(ownerId:1)
    allJobsByOwner(ownerId:2)
    allJobsByOwner(ownerId:3)
etc..

I was under the impression that the query could not be re-fetched without re-applying the arguments back to query in refetchQuery. But if you supply strings to refetchQueries apollo will look them up by name and re-run them with the last variables applied.

For those curious please see:

https://github.com/apollographql/apollo-client/blob/3b5045dfe74183fe060d2027e31317d890755b99/src/core/QueryManager.ts#L1305-L1322

and

https://github.com/apollographql/apollo-client/blob/3b5045dfe74183fe060d2027e31317d890755b99/src/core/ObservableQuery.ts#L207

Confirmed that this worked. Might be worth highlighting that the query name comes from the operation name. I missed that in steve-a-jones's example, and it tripped me up for a few minutes. So:

query thisIsWhatYouPassToRefetchQueries($ownerId: ID!) {
  doNotPassThisToRefetchQueries(ownerId: $ownerId) {
    ...
  }
}

The solution with refetchQueries works, however, what if we are not to poll the data from a server, but instead write it to cache straight away. It can be done with readQuery and writeQuery but it's tricky since you'll need to provide the exact same variables to the query as in a cache.

Is there any way round it?

Also what happen if you and to update/refetch in ALL the variables not just the last variables applied

A couple of peeps at Xero came up with a middleware-esque pattern to tackle this sort of concern: apollo-link-watched-mutation.

Could we reopen this? I feel like the use case @snaumov mentions ("what if we are not to poll the data from a server, but instead write it to cache straight away") is still unsolved. I would be curious to hear from the Apollo team on this and know if they suggest using the Watched-Mutation pacakage or if there's another way?

@SachaG I was able to solve the mentioned problem of not knowing which arguments to use for a cached query here:
https://www.apollographql.com/docs/react/advanced/caching.html#connection-directive
so, essentially, if the query has @connection directive in it, in the cache it'll be stored without extra arguments.

Good to know, thanks! In the end I decided to go with watched-mutation because my update functions are not really aware of my queries (they're handled by different components).

The solution with refetchQueries works, however, what if we are not to poll the data from a server, but instead write it to cache straight away. It can be done with readQuery and writeQuery but it's tricky since you'll need to provide the exact same variables to the query as in a cache.

Is there any way round it?

this was what came to my mind too, but I can't believe that this is the only way… like storing all the previous filters and updating them accordingly doesn't sound like an optimal solution to me, too many cases to handle. In my case there was a status change of an item from pending to failed, which in UI should be updated by filter with 3 statuses (in pending should be removed, failed: should be added, any: status should be updated)
In this example there are only 3 different cases to handle which should be okay, but it can escalate really quickly. And even handling it with update doesn't sound perfect, because of pagination, in failed there will be one more element which could cause issues and in pending will be one fewer which also could lead to some issues.

Should I just go with refetchQueries and that's it or do you have any ideas for this case?

@SachaG I was able to solve the mentioned problem of not knowing which arguments to use for a cached query here:
https://www.apollographql.com/docs/react/advanced/caching.html#connection-directive
so, essentially, if the query has @connection directive in it, in the cache it'll be stored without extra arguments.

@snaumov Thanks a lot for that point! Worked for me.

Was this page helpful?
0 / 5 - 0 ratings