Apollo client cache mutations ignoring where condition

Hi,

Probably quick question here, I have a readQuery that reads a query previously run on the server side in Next.js, it looks for patients that have a specific user assigned to them (with ID of 40):


const queryResult = apolloClient.readQuery({

    query: GET_PATIENT_USERS,

    variables: {

      orderBy: [{ patient: { name: "asc" } }],

      where: { userId: { equals: 40 } },

    },

  });

If I use writeQuery or writeFragment or anything else, it adds the new entry automatically without accounting for the where condition, per the below (where I’ve specified user ID to be 39 which does not match the original query that pulled from ID 40)


client.writeQuery({

        query: GET_PATIENT_USERS,

        variables: {

          orderBy: [{ patient: { name: "asc" } }],

          where: { userId: { equals: 40 } },

        },

        data: {

          patientUsers: [

            ...existingPatientUsers.patientUsers,

            { ...data.addPatientUser, userId: 39 },

          ],

        },

      });

This adds a new entry to the list regardless of the fact the user ID does not match (completely ignoring the where condition).

I’m not sure if that’s because my query was run on the server originally instead of the client? Is this something I can solve?

Appreciate any assistance.

The client cache is in-memory, so if you run a query on a different machine it will definitely not be cached.

You can cache things on the server side, too, per the Apollo docs, but the behavior is a little hard to immediately predict in my experience.

If you need to cache things closer to the server, redis or a library like mem with a TTL on the value would probably be a good starting place.

I know the server query is not being cached, that’s why I’m passing the server’s current state to the Apollo client running on the client then running the readQuery. per the below:


  const apolloClient = React.useMemo(() => {
    return initializeApollo(initialState);
  }, [initialState]);

Setting aside the server side component, both the readQuery and the writeQuery I included are being run on the client side so I’m still wondering should the where condition in the readQuery be filtering any objects added through the writeQuery? Does the code need to be changed / is this something Apollo client supports or do I need to do the filtering myself?

I could be completely wrong and I’d be happy to learn more about it, but is there a where or an orderBy on this API?

I think where and orderBy need to be carried out within your resolver on your server.

Then to get the matching data out of the cache via readQuery, you just run the same query with the same variables as you did to initially retrieve the data, and a fetchPolicy that’s going to access the cache.

If you want to access a particular object in the cache, you can specify it by id, e.g.

client.writeFragment({
	id: `Appts:${appt.id}`,
	fragment: gql`
		fragment appt on Appts {
			hasBeenSeen
		}
	`,
	data: {
		hasBeenSeen: true,
	},
});

Also – using React.useMemo on an Apollo state object seems non-standard and may have unexpected results. Please let me know if this is an approach recommended by Apollo.

Hopefully the above notes are helpful.

Appreciate the response,

I think that is a good point that the where and order by are being handled by Prisma on the server and not by Apollo client itself so I shouldn’t assume without communication to the server again that Apollo client will apply the results of those variables when the cache changes.

My problem revolves around the fact that I have 2 of the same query using the same type (patientUser) and the same mutations (adding a new item) and the new items are showing up in both, maybe I’ll look for a way to separate them.

It’s usually good to have one query used in more than one place. Why is it preferable to avoid having the new items all in one place?

The root query cache keys are formed using the field name (patientUsers) and the JSON stringified variables (your combination of orderBy and where). If you add another item to that very root query using cache.writeQuery, it doesn’t matter what userId your new item has. You told the part of the cache with where: { userId: { equals: 40 } } to take this new item with userId: 39, so that’s what it does. If you want it added to a matching root query, you’ll have to use where: { userId: { equals: 39 } } in the variables instead.

Thank you for the all the help,

I think that gave me a better understanding of the state management. That was the solution I ended up with (separating the queries), which logically separated the state.

No problem. If you’d like to learn more on how the cache works and how to properly manipulate it, may I suggest this lengthy caching guide I wrote a little while ago? That should help clear up some of the trickier issues.