Why store.findAll is reloading view and store.query is not?

At the moment, when an article is added to the store, my view is not updated when I use store.query(), filtering server side, in my route but it’s updated when I use store.findAll() with filtering client side.

With findAll, filtering client side

//route.js
model() {
return this.get('store').findAll('article');
}

//controller.js
articleSorted: computed.filterBy('model', 'isPublished', true),

and with query filtering server side

//route.js
model() {
  return this.get('store').query('article', { q: 'isPublished' }),
}

The fact is that findAll is reloading and query is not.

I’ve found this but did not understand https://github.com/emberjs/ember.js/issues/15256

I think this is a common tripping point for people (myself included). The problem is that “findAll” means, quite literally, “all” so it’s easy to infer that yes, if there is a new record it should be added to the results. Query is different though. A query result array is like a single snapshot of data state frozen in time. A query is like saying to the API “hey, give me all the records that meet x criteria RIGHT NOW”. And that x criteria could be any arbitrary thing that your API supports. Once you have the results of that query the backend and the front-end could become out of sync and the front-end has no idea how to correctly update the query results.

Let’s say you are requesting paged data from a collection of users in a large system, you might have a query like this:

store.query('user', { created_after: "2019/01/01", page: 3, perPage: 10 });

So the backend returns you 10 user records, sorted by last name (the default sort in this contrived hypothetical situation). Now while you the user are checking out these 10 users someone else creates another user, and it just happens to be the 26th user “sorted by last name” so if you were to run the query again the new user would be in the new results and the last user from the old results would be pushed out into page 4.

Further let’s imagine that somehow your app loaded the new user record separately. So now you have the new user record in the store, and you have the 10 previously fetch user records in the store, and probably some other random ones too. And let’s imagine you’re still looking at the third page of users and haven’t done anything else. Your front-end has all the records the backend does, but it doesn’t have proper context to dynamically modify the query results. The API is the source of truth for how to translate a query into a collection of records, and your front-end doesn’t (and shouldn’t) know how to replicate that. The only way to meaningfully “update” a query then is to refetch, getting the most recent results snapshot from the source of truth, the API.

As another example what if you had a query that was like store.query('user', { random: true }). How would the front-end know how to “live-update” those results?

TLDR: query creates infinite potential complexity in terms of how to “sync” the back-end data and front-end data.

This problem seems to arise from the desire to have “basically a findAll but with <simple filter or query param>”. Believe me I’ve been there. It’s a little awkward but the most straightforward (both conceptually and in terms of the framework) solution is to fetch the records you want via query or whatever other means you like, and then user a filtered peekAll to filter down what you have in the store to what you want (which will live update).

1 Like