2

I am using Firestore with AngularFire and am currently trying NgRx for a new feature. As recommended, I am using collectionChanges instead of collectionData, to only subscribe to the incoming changes instead of getting a whole update of the full data every time.

This works fine when there is data in the collection. Initially, I am getting a list of "added" events, and then "modified", "removed", and "added" as they are happening.

The problem is that when the collection is empty, I am not getting any event, so I cannot switch from loading to an empty view.

I would expect to receive an empty array of DocumentChanges at the initial load, but this does not happen. My current workaround is to listen to collectionData additionally and merge the first result to the collectionChanges subscriptions if it is empty.

This seems like an ugly hack. Is there a better/cleaner solution?

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Paul Weber
  • 6,518
  • 3
  • 43
  • 52
  • 1
    You should look at the [startWith operator](https://rxjs.dev/api/operators/startWith). – Octavian Mărculescu Apr 29 '22 at 07:17
  • Well, I want to wait until I am sure that the query worked and there are definitely no results, else there would be a flashing no items screen and then the items loading. – Paul Weber Apr 29 '22 at 07:21
  • As stated in the doc, [collectionChange][1] does only print the changes. So if the collection is empty, no change are returned, that makes sense. Approach by loading first the collection makes sense, because you first load the state of the collection, then the changes. But be carrefull to add something like `pipe(take(1)` not to make more than 1 call to the db. [1]: https://github.com/FirebaseExtended/rxfire/blob/main/docs/firestore.md#collectionchanges – Antoine Xevlabs May 05 '22 at 13:54

1 Answers1

2

As recommended, I am using collectionChanges instead of collectionData, to only subscribe to the incoming changes instead of getting a whole update of the full data every time.

According to the official documentation regarding collectionChanges() function, it is said that:

The collectionChanges() function creates an observable that emits the changes on the specified collection based on the input query.

What is not specified there, is that it emits the changes on the specified collection (only if the collection exists).

This works fine when there is data in the collection. Initially, I am getting a list of "added" events, and then "modified", "removed", and "added" as they are happening.

That's the expected behavior since your collection already contains documents. So once you get the initial data, you can then later get all events as they occur.

The problem is that when the collection is empty, I am not getting any event, so I cannot switch from loading to an empty view.

It makes some kind of sense because when a collection in Firestore doesn't contain any documents, that collection doesn't exist at all. A collection will start to exist only when there is at least one document present. Please note that the collections in Firestore don't work like filesystem directories. There is no way you can create an empty collection. The collections are always tied to the documents they contain.

I would expect to receive an empty array of DocumentChanges at the initial load, but this does not happen.

To be honest it makes sense again since we cannot expect to get an event from a collection that actually doesn't exist.

My current workaround is to listen to collectionData additionally and merge the first result to the collectionChanges subscriptions if it is empty.

While your workaround will definitely work, I don't think it's the best option that you have.

This seems like an ugly hack. Is there a better/cleaner solution?

It's not ugly but it will most likely imply a lot of reads. So if your collection contains a lot of documents, you'll be billed with one read operation for each "added" document it exists in the initial event.

So in my opinion, there are two ways in which you can solve this.

The first one would be to always create a dummy document, so your collection will start to exist. Or, you can check if the collection is empty. How can you do that? Simply by performing a query and limit the results to one. Then check the size of the query document snapshot. In this way, you'll always know if the collection is empty or not. So knowing this, you can only use collectionChanges() if the collection contains at least a document. That being said, you'll have to pay a single document read for checking that. However, you'll still be charged with one document read, even if your query yields no results.

So no matter what the query returns, you'll always need to pay only one document read.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • 1
    Hey Paul. Can I help you with other information? – Alex Mamo May 08 '22 at 06:25
  • Hey! Sorry, I was in the weekend. Nice solution with the limit 1 query, but it's a little bit complicated for me, since I need to sync multiple queries with different query parameters. Yeah, I got another question! What happens if the collection exists (with documents) but there are no documents selected by the query? – Paul Weber May 10 '22 at 11:53
  • If the collection exists but your query doesn't return any results, then you'll get an empty snapshot. But isn't the same as trying to query a collection that doesn't exist. – Alex Mamo May 10 '22 at 13:01