Apollo GraphQL merge cached data

10,771

Solution 1

Solved!

 cache: new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          YOUR_FIELD: {
            merge(existing = [], incoming: any) {
              return { ...existing, ...incoming };
              // this part of code is depends what you actually need to do, in my 
              case i had to save my incoming data as single object in cache
            }
          }
        }
      }
    }
  })
});

Solution 2

Here is the same solution mentioned by Thomas but a bit shorter

const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        YOUR_FIELD: {
          // shorthand  
          merge: true,
        },
      },
    },
  },
});

This is same as the following

const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        YOUR_FIELD: {
          merge(existing, incoming, { mergeObjects }) {
            return mergeObjects(existing, incoming);
          },
        },
      },
    },
  },
});

Solution 3

The other answers still work, but as of Apollo Client >= 3.3 there's an easier option that doesn't require specifying specific fields or a custom merge function. Instead, you only have to specify the type and it will merge all fields for that type:

const cache = new InMemoryCache({
  typePolicies: {
    YOUR_TYPE_NAME: {
      merge: true,
    }
  }
});

From your example query, I'd guess that an id field should be available though? Try requesting the ID in your query, that should solve the problem in a much more ideal way.

Solution 4

Had same issue with inconsistency of data values vs. our schema. A value type within an entity was missing the id value. Caused by an incomplete data migration.

Temporary solution:

const typePolicies = {
      PROBLEM_TYPE: {
        keyFields: false as false,
      },
      PARENT_TYPE: {
        fields: {
          PROBLEM_FIELD: {
            merge: true
          }
        }
      }
    }
Share:
10,771
Thomas Rositsky
Author by

Thomas Rositsky

Updated on June 14, 2022

Comments

  • Thomas Rositsky
    Thomas Rositsky almost 2 years

    I have a page that consists of 2 components and each of them has its own request for data for example

    <MovieInfo movieId={queryParamsId}/>
    
    const GET_MOVIE_INFO = `gql
      query($id: String!){
       movie(id: $id){
        name
        description
     }
    }`
    

    Next component

    <MovieActors movieId={queryParamsId}/>
    
    const GET_MOVIE_ACTORS = `gql
      query($id: String!){
       movie(id: $id){
        actors
     }
    }`
    

    For each of these queries I use apollo hook

    const { data, loading, error } = useQuery(GET_DATA, {variable: {id: queryParamsId}}))

    Everything is fine, but I got a warning message:

    Cache data may be lost when replacing the movie field of a Query object. To address this problem (which is not a bug in Apollo Client), either ensure all objects of type Movie have IDs, or define a custom merge function for the Query.movie field, so InMemoryCache can safely merge these objects: { ... }

    It's works ok with google chrome, but this error affects Safari browser. Everything is crushing. I'm 100% sure it's because of this warning message. On the first request, I set Movie data in the cache, on the second request to the same query I just replace old data with new, so previous cached data is undefined. How can I resolve this problem?

  • xadm
    xadm almost 4 years
    using id in both queries does the same
  • Admin
    Admin over 3 years
    I had a similar issue and I am retuning ids in both, but it doesn't work for me @xadm
  • Baruch
    Baruch over 3 years
    @xadm My man... was about to start pulling my hair before I saw your comment.
  • Tyler
    Tyler almost 3 years
    I'm confused; why wouldn't that be the default behavior for types with an id field. Apollo can tell two objects are the same object if they have the same id, so just merge them.
  • Ben Regenspan
    Ben Regenspan almost 3 years
    @matrixfrog it is the default behavior for types with an id field, this setup is only for special cases where one is not available for whatever reason (definitely preferable to design the API side such that this isn't necessary). (Just updated my answer to be clear on this)
  • Tyler
    Tyler over 2 years
    Okay that makes sense, but I was still getting a warning, even with ids on all objects. However, since posting that comment, I think I solved it by upgrading to the latest Apollo Client version.