Apollo-client: Merging subtrees in cache

Created on 3 Oct 2018  ·  9Comments  ·  Source: apollographql/apollo-client

I've got two queries with overlapping subtrees (shown below). In the editorsQuery, the id of the currentVersion might be different than in the documentQuery, because someone might have updated the document in the time between the first and the second query. If that happens, Apollo seems to return an empty object wherever the documentQuery is used. If I inspect the cache in the Apollo devtools, the second query overwrites the currentVersion completely, leaving out the downloadUrl because it's not included in the editorsQuery. Is there a way to instead merge the two results? The queries used in this example are of course fictional, but we have many of these types of queries in our application.

query documentQuery {
  document {
    id
    currentVersion {
      id
      downloadUrl 
    }
  }
}
query editorsQuery {
  document {
    id
    currentVersion {
      id
      editors {
        id
        name
      }
    }
  }
}

I've made a reproduction of this issue on CodeSandbox:

Front-end: https://codesandbox.io/s/k0wm12zpqr
API: https://codesandbox.io/s/k282yz01p7

Make sure to open the CodeSandbox for the API because the server may have shut down in the meantime. You might have to refresh the front-end until the API is back up :)

✔ confirmed 🐞 bug

Most helpful comment

I am having issues where other queries are overwriting previous queries and nullifying data that should just be merged. Not sure how to resolve it.

All 9 comments

Thanks very much for the reproduction! This is definitely a bug, not the intended behavior.

After digging into this a bit deeper, I think part of the problem is that you're generating a new UUID every time you evaluate the Document.currentVersion resolver on the server. So there is never any Version object that comes back from the server with both downloadUrl and editors.

While I think it might be reasonable to display the new currentVersion object (with editors but _without_ downloadUrl) after the button is clicked, showing a downloadUrl for that Version object would require fetching the Document from the server again, but that would give you a new currentVersion.id (because that resolver would run again), which would repeat the problem.

In other words, I don't think we can provide a satisfactory solution unless you keep your Document.currentVersion.id values somewhat stable. I realize you're just trying to fake some data, but this particular kind of fakery breaks the conceptual model of the system.

We already merge fields for result objects that have the same ID, as you can see if you stick to just one currentVersion.id. We're definitely not going to start merging fields from objects with different IDs, if that's what you were hoping.

Hi @benjamn, thanks for taking the time to look at this issue. I think I haven't explained my situation well enough. You're right in noticing that the id of the Version changes every time, I did this purposefully because this is something that might happen in our application. For example: a user might be viewing a document (documentQuery) and some time later they might do something that triggers a query that queries fields from currentVersion (editorsQuery), if the id of currentVersion has changed in the meantime (this might happen when someone else updates the document between the two queries) the application will be in an incomplete state because all other data of currentVersion is wiped away from the cache. I'm certainly not expecting any sort of automatic resolution and I fully understand why Apollo reacts this way when the ids don't match up. But I was hoping that maybe I could somehow manually merge the two currentVersion objects.

@TimonVS
In your case, I guess you have to provide other some kinda key as sticky value.
Fortunately we can change key name of id each types.
see https://www.apollographql.com/docs/react/advanced/caching.html#normalization

On below example I'm using documentId of Version as id key and it works well.

FrontEnd: https://codesandbox.io/s/mm89lpmnp
API: https://codesandbox.io/s/pjx76125wj

Interesting solution @joe-re! I will have to further experiment if this can be a solution to our problem.

i’m facing this bug too

We already merge fields for result objects that have the same ID, as you can see if you stick to just one currentVersion.id. We're definitely not going to start merging fields from objects with different IDs, if that's what you were hoping.

Although currentVersion changes, this is a subfield of Document, and the document id does not change, so I'd at least expect the parent document to be un-affected even if currentVersion needs replacing.

I am having issues where other queries are overwriting previous queries and nullifying data that should just be merged. Not sure how to resolve it.

This is still an issue for me, is there something simple I'm missing?

Was this page helpful?
0 / 5 - 0 ratings