-
Notifications
You must be signed in to change notification settings - Fork 786
Updating cached data from multiple parameterized queries after a mutation #708
Comments
By default mutations updates happens based on node's id that are returned from the If that is not enough, you might need define the You can find more information in the docs her: http://dev.apollodata.com/core/read-and-write.html#updating-the-cache-after-a-mutation |
and then for different kind of mutations I would need a way to update the data in the store: delete the node from the store in the case of a If not, any idea of how to update the cache using As an example of a use case, in a pagination scenario, I could have dozens of calls to a certain query (that loads each successive page), each of those calls having different variables (relating to the loaded page). Suppose I then mutate an item from the results of one of those queries. How would I go about updating the correct query results in store? I thought about using How do I update all queries that contain the |
You don't need to update all queries, you just need to update the item in the store which was mutated and apollo will update all references to related to that item. Example: // We assume that the GraphQL operations `DeleteToDo` and
// `TodoAppQuery` have already been defined using the `gql` tag.
const id = 42
client.mutate({
mutation: DeleteToDo,
variables: {
id,
},
update: (proxy, { data: { deletedToDoId } }) => {
// Read the data from our cache for this query.
const data = proxy.readQuery({ query: TodoAppQuery })
// Remove the deleted todo
data.todos.filter(todo => todo.id !== deletedToDOId)
// Write our data back to the cache.
proxy.writeQuery({ query: TodoAppQuery, data })
},
}) If your server doesn't return the id of the deleted item you still have the id that you passed into the mutation variable. Ps: If I didn't get your issue right can you comment some code snippets so I can reproduce what you are trying to achieve? |
This issue has been automatically marked as stale becuase it has not had recent activity. It will be closed if not further activity occurs. Thank you for your contributions to React Apollo! |
Potentially apollographql/apollo-client#1821 is related as well? |
You can define the key name via a connection directive now... |
I'm running into a similar problem. When a query accepts one or more variables I want to either refetch or update that query with all possible variables it has been cached with. Use-case is something like adding to or removing items from the top of some infinite scroll list or paginated results. In my case it's a query that retrieves just the right amount of items that fit on the screen. const query = gql`
query ItemQuery($first: Int) {
items: allItems (first: $first, orderBy: createdAt_DESC) {
id
}
}
`; This query gets executed a few times with results as follow: // $first === 3 (default)
items === [7, 6, 5]
// $first === 6 (after react-measure adjustments)
items === [7, 6, 5, 4, 3, 2] If I add a new item with // $first === 3
items === [8, 7, 6]
// $first === 6
items === [8, 7, 6, 5, 4, 3] How do I do that? |
This issue has been automatically labled because it has not had recent activity. If you have not received a response from anyone, please mention the repository maintainer (most likely @jbaxleyiii). It will be closed if no further activity occurs. Thank you for your contributions to React Apollo! |
This issue has been automatically closed because it has not had recent activity after being marked as no recent activyt. If you belive this issue is still a problem or should be reopened, please reopen it! Thank you for your contributions to React Apollo! |
Did anybody find a proper solution here? I think this is a use-case a lot of people will run into and the feedback provided by @lucasfeliciano doesn't cover that. Let me try with another Example: You have a list of "Liked Objects". But this list is filterable by color. So your query would look like this: getLikedObjects(userId: $id, colors: $color) ... The user calls the query 3 times with colors: null, colors: [blue] and colors: [yellow, blue] Now the cache will have 3 entries for that query (based on different variables). Entry 1 (colors: null): [Object 1, Object 2, Object 3] Now imagine the user unlikes "Object 3". This would mean we can't just wipe out the Object in the Cache using dataIdFromObject with readFragment --> We wan't to keep the Object itself in the Cache but only remove it from the "getLikedObjects"-Queries that contain it (Entry 1 and Entry 3). But we don't know how many times the user has filtered with what values... So what we would like to do is: Remove Object 3 from all getLikedObjects-Queries that contain it – regardless of any variables provided to the query So a more flexible way to match Queries in "readQuery" as suggested by @c10b10 (for example using Regex) would work…!? |
@protyze In here |
Any update on how to solve this problem |
As it is already normalized, I feel like there should be an API to read data from the cache as if it were a classic This reading of values using queries (or fragments) as inputs looks awkward and forces overlapping of responsibilities by having to pass around things, like query strings or user inputs that determine It's unfortunate to see this issue closed, by the way. |
@nfantone I agree, There should be a way to bust the cache for a regex / loose match like what redis has would be amazing! I hate having to pass around the original Query or recreate the original query just to get at some object data. I know I can hack things and access the cache directly and delete things but it is a big work around. The current state of things makes pagination cache busting impractical. Its better to just clear the whole cache. This API really needs to get updated please! |
This is an issue for me too. I have a query (
|
@sandorvasas For this kind of issues, you can use the |
This is a massive shortcoming in Apollo in general (whether using it with React, Vue, plain JS). Results from queries using variables like sort/sortBy are all cached separately. There needs to be a built-in utility to handle this. |
Still no solution? |
I would also love to see such a feature part of the cache API. Meanwhile, for those who are interested, I've created a function to get all variants of a query in the cache. It accepts an instance of the Here is the gist (only tested with Example update: (proxy: any, { data: { addTask } }: any) => {
const query = QUERY_TASKS
const variablesList = getVariablesListFromCache(proxy, query)
for (const variables of variablesList) {
const data = proxy.readQuery({ query, variables })
data.tasks.push(addTask)
proxy.writeQuery({ query, data })
}
} |
To anyone with this same problem today: the here is an example of its usage: https://stackoverflow.com/a/48262766/3068233 |
It's been months since I was working with this, but I remember |
@ngryman made my day. It works perfectly with Apollo-client 2.6.3 in a case where apollo-link-watched-mutation does not seem to work anymore. It also works after server side rendering, when the queries haven't been run yet. However I need to match on the resolver name, not on the query, see my comment on the gist. I've had it to work with a delete mutation. Creation is more complex because some queries might have filtering but it's doable. |
@connection directive is meant for cases where you have an infinite list. Is not meant for numbered pages pagination (unless you do all the split yourself for every page/rowsPerPage) . Even with @ngryman solution, it won't work for cases where you are inserting a new item, because you don't know where you have to put it in different queries with different variables, for example if you have a sorted list. I guess this is not a big deal since nobody for the apollo team had addressed this issue. 🤷♂️ |
Suppose I have a paginated infinite scroll list of
Items
. The list pulls data from a GraphQL server by using two parameterized queries:ITEMLIST_QUERY
andITEMLIST_MORE_QUERY
. Both of those queries have arguments for ordering, and filtering, and whatever else is needed for pagination. The only difference between them is that theMORE
query has an extra$skip
argument (I know I could have used a single query with a default$skip
set to0
, but the question stands, since I could have the same query called with different variables).Now suppose a user loads a few pages of data, ie.
ITEMLIST_QUERY
gets called at component mount, data is loaded into the store, first 10Items
are rendered on the page.ITEMLIST_MORE_QUERY
gets called with a$skip: 10
arg, data is loaded into the store, the 10 new items are appened in the UI.ITEMLIST_MORE_QUERY
gets called again with a different$skip
, data is loaded into the store, the UI now contains 30 `Items.Now suppose the user clicks
Delete
for a certain item in the list, and theITEM_DELETE_MUTATION
mutation gets called.How does one update the data for the appropriate query in the store (with the mutated data) by using the recommended
update
in ordered to update the UI to reflect the deletion?proxy.readQuery
seems to not be able to help, since I can't be sure of the number of queries executed, or of which query contains the deletedItem
.Is there a way to get all data from all queries that match a certain pattern? For example:
Is there a way of doing this by using
update
? The only way I can think of is to manually save the queries that I want to reset (with their variables) in the store, and then reset them after each mutation.The text was updated successfully, but these errors were encountered: