Hi folks -
I'd be happy to help clarify some of the underlying client behavior. Be sure to follow-up with me if anything said below is unclear.
That conclusion around what data is cached for the different listeners isn't quite right. In actuality, all of the client events (added, changed, removed, and moved) load the same data from the server and cache it on the client.
The best way to see exactly what data is going over the wire is to enable logging in the client. Here's how to do that on the various clients, generally at the beginning of the app:
Firebase.enableLogging(true);
[Firebase setLoggingEnabled:YES];
Firebase.getDefaultConfig().setLogLevel(Logger.Level.DEBUG);
Adding a single 'child-removed' or 'child-changed' (or any child event) listener to the root of a list in Firebase, without any limits or offsets, will download the entire list to the client. There are important reasons for this behavior, largely boiling down to the fact that Firebase does state synchronization instead of pub-sub, so from the perspective of a Firebase client there is no notion of "only give me events since I came oneline". Let's dig a bit deeper on that subject:
The two biggest reasons for this client behavior worth calling out are (a) offline behavior, and (b) local events, which go hand-in-hand. In the former case, if you had a 'child-removed' event listener established with the server, but went offline, when you came back online we wouldn't know which elements to send down to your client unless we persisted each of those removed elements on the server indefinitely. By sending all elements in your defined window down to the client, when the client comes back online we can invoke your callback / block to tell you precisely which children were removed from the list. Similarly, for local events, if you went offline and your local client removed items from the list or cleared it entirely, we can immediately fire local events with the "correct" state of the data.
It is, admittedly, a little unintuitive that the 'child-removed' event would load the full list on the client. In general, if you're working with large lists in Firebase, the best way to restrict the amount of data being transferred is to always use one form of limiting / windowing or another - generally using two of the three methods in (`startAt()`, `endAt()`, and `limit()`).
I hope that helps, and let me know if I can assist with anything else.
Have a great weekend -
Rob