0

I'm to get an answer on whether or not the way my database is setup will cause too many recursive reads and therefore exponentially increase the number of read operations.

I currently have a collection of users, inside of each user doc, I have 3 other catalogs, goods, bundles and parts. Each user has a list of parts and a list of bundles, for example.

Each doc in the bundles catalog has an array of maps with a reference to a doc in the parts catalog in each map.

When I query the bundles, I want to also get the details of each part in the bundle. Does this require that I run another onSnapshot?

Here's an example:

database:

  users (catalog)
    userID
      parts
        partID1
        partID2
        partID3
      bundles
        bundleID1
          title: "string",
          parts: [
            part:"/users/userID/parts/partID1,
            qty: 1
          ]
          parts: [
            part:"/users/userID/parts/partID2,
            qty: 1
          ]
          parts: [
            part:"/users/userID/parts/partID3,
            qty: 1
          ]

getting the bundles

  initBundle(bid) {
    const path = this.database.collection('users').doc('userID').collection('bundles').doc(bid);
    path.ref.onSnapshot(bundle => {
      const partsArr = [];
      bundle.data().parts.forEach(part => {
        part.part.onSnapshot(partRef => {
          const partObj = {
            data: partRef.data(),
            qty: part.qty
          };
          partsArr.push(partObj);
        });
      });
      const bundleObj = {
        title: bundle.data().title,
        parts: partsArr
      };
      this.bundle.next(bundleObj);
    });
    return this.bundle;
  }

I'm using Ionic/Angular for this, so when I return the item, it needs to be an array of objects. I'm sort of recreating the object to include each part on this init. As you can see, for each part in the bundles return, I am doing another onSnapshot. This seems incorrect to me.

Something that is dawning on me is that I probably should be making a single call to the user, which in turn returns everything? But how do I get the sub catalogs at that point? I'm not sure how to proceed without racking up a bill!

ntgCleaner
  • 5,865
  • 9
  • 48
  • 86
  • "I'm just trying to get a straight-forward answer on whether or not the way my database is setup is going to cost me too much in read actions." I recommend rewriting your question to focus on the number of read/write operations you'll be charged for, instead of the cost (which depends on other factors too), and whether this cost is too much (which is subjective). – Frank van Puffelen Feb 24 '19 at 15:03
  • @FrankvanPuffelen Thank you, I will re write this here. – ntgCleaner Feb 24 '19 at 18:22
  • Came up with a simple solution for optimized querying to firestore for clients who are extremely cautious with their price plan. [The implementation](https://stackoverflow.com/a/63673175/5223309) is pretty simple, have a look. – Shababb Karim Sep 01 '20 at 17:17

1 Answers1

1

If you do a nested part.part.onSnapshot(partRef => { listener, be sure to manage those listeners. I know of three common approaches:

  1. Once your outer onSnapshot listener disappears, the nested ones should probably also be stopped (as their data likely isn't needed anymore). This is a fairly simple approach, since you just need one list of listeners for the entire bundle

  2. Alternatively you can manage each "part" listener based on the status of that part in the outer listener, removing the listener for "part1" when that disappears from the bundle. This can be made into a highly efficient solution, but does require (quite some) additional code.

  3. Many developers use get()s for the nested document reads, as that means there is nothing to manage.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • It seems a quick short-term solution is the `.get()` rather than `.onSnapshot()`. I haven't been able to test yet, but going from Firebase to Firestore, I'm trying to wrap my head around the extra functionality. I know with Firestore it's a simple flat file and if I were to query the user, I'd inherently get all of the parts, bundles, etc. (but no references). Is this not the case with firestore? Can I not just query the user and inherently get all of the information under that catalog? – ntgCleaner Feb 24 '19 at 18:28
  • Reads are shallow on Firestore. They will only read documents from a single collection, never from multiple collections (neither subcollections nor other top-level collections). – Frank van Puffelen Feb 24 '19 at 18:46