6

I am designing a Firestore Database and am wondering about the cost implications of the following architecture...

Following cloud Firestore tutorials, lets imagine this architecture: A 'Restaurants' Collection has a 'Reviews' subcollection. Something like:

--Restuarants
   --My Restaurant
      --Reviews
         --My Review 1, through n

I am interested in querying the reviews subcollection, but I am not really interested in the review itself, but on the restaurants.

So, for instance, in a query like Get all reviews posted on August 1st 2019 I am actually interested in the restaurants that have at least one review posted on August 1st 2019. ie. I would like to get back the restaurants' documents, not the reviews.

From this post and this it seems like my implementation would probably look something like this:

    QuerySnapshot myQuerySnapshot = await Firestore.instance.collectionGroup('reviews')
                .where('reviewDate', isEqualTo: '20190801').snapshots().first;
    List<DocumentSnapshot> myDocumentSnapshots = myQuerySnapshot.documents;

    myDocumentSnapshots.asMap().forEach((index, son) {
          snapshot.reference.parent().parent().get().then((parent) {
            print("Printing snapshot: $index");
            print("son id: "+son.documentID);
            print("parent id: "+parent.documentID); //I could then retrieve the parent data.
            });
    });

With this implementation, I would be fetching all the 'sons' (ie. all the reviews). This has a couple of disadvantages:

  • Cost. A restaurant may have, say, 1000 reviews posted on august 1st 2019; I would be charged for 1001 reads (1000 reviews + the actual parent document I am interested in).
  • Data consumption. My users would retrieve way more data from the servers than what is actually needed.

Is there a better way to do this? Is there a way to avoid fetching the reviews and getting only the parent documents?

Thanks!

Andres Silva
  • 874
  • 1
  • 7
  • 26
  • This is relational data and would be better suited to a traditional database and not a document store. –  Jul 20 '20 at 02:36
  • Does this answer your question? [Cloud Firestore collection count](https://stackoverflow.com/questions/46554091/cloud-firestore-collection-count) – Ken Y-N Jul 20 '20 at 02:37

1 Answers1

3

There is no way to get back restaurants when you're querying the reviews collection(s). So what you're doing is the only way to get the restaurants without changing your data model.

As usual when dealing with NoSQL databases, it may be better to modify your data model to better suit this use-case. The quick alternative I can think of is to keep an array datesWithReviews in the restaurant document, which you update whenever you add a review to the reviews subcollection of that restaurant. If you use an array-union operation to update the array, you can update the restaurant whenever a review is added for a date, without having duplicate dates in the array.

With that field in each restaurant document, you can then query across all restaurants that contain that date. If you store the dates as simple "2020-07-19" strings, that query would look like:

firebase.firestore().collection("restaurants").where("reviewDates", "array-contains", "2020-07-19")

This is similar to how restaurant ratings are updated when a review is added in the FriendlyEats codelab step on writing data in a transaction. Also see the video walkthrough of that step.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807