1

Here is my problem:

I have a firestore collection that has a number of documents. There are about 500 documents generated/updated every hour and saved to the collection.

I would like to query the collection and setup a real-time snapshot listener for a subset of document IDs, that are provided by the client.

I think maybe I could to something like this (this syntax is likely not correct...just trying to get a feel for if it's even possible...but isn't the "in" limited to an array of 10 items? ):

const subbedDocs = ["doc1","doc2","doc3","doc4","doc5"]
docsRef.where('docID', 'in', subbedDocs).onSnapshot((doc) => {
   handleSnapshot(doc);
   });

I'm sorry, that code probably doesn't make sense....I'm still trying to learn all the ins and outs of Firestore.

Essentially, what I am trying to do is take an array of ID's and setup a .onSnapshot listener for those ID's. This list of IDs could be upwards of 40-50 items. Is this even possible? I am trying to avoid just setting up a listener on the whole collection and filtering out things I am not "subscribed" too as that seems wasteful from a resources perspective.

Donnald Cucharo
  • 3,866
  • 1
  • 10
  • 17
pilotGuy
  • 111
  • 1
  • 10
  • Can add a little detail about the docs and what's in them? (this is what's kept me from writing my own answer). It's an odd premise that the client supplies docIDs. I think you should think of doc IDs as internal to the back-end. – danh Aug 05 '21 at 02:14

2 Answers2

1

If you have the doc IDs in your array (it looks like you have) you can loop over them and start a listener during that:

const subbedDocs = ["doc1", "doc2", "doc3", "doc4", "doc5"];

for (let i = 0; i < subbedDocs.length; i++) {
  const docID = subbedDocs[i];

  docsRef.doc(docID).onSnapshot((doc) => {
    handleSnapshot(doc);
  });
}

It would be better to listen to a query and all filtered docs at once. But if you want to listen to each of them with a explicit listener that would do the trick.

Tarik Huber
  • 7,061
  • 2
  • 12
  • 18
  • How would you recommend I "listen to a query and all filtered docs at once." I guess ultimately that's what I want to do. How would I query Firestore for just the document id's in the array, and then attach a listener to that? – pilotGuy Aug 04 '21 at 22:01
  • @pilotGuy, all of those listeners can invoke handleDoc(doc), and it can aggregate them in an array, I think what you're looking for in effect. See my comment on the other answer. Why those docs? If you can articulate that in a query (not a query for their doc ids), then just query and listen to the querySnapshot. – danh Aug 04 '21 at 22:19
  • I did not suggest a change of the database structure because I don't know what you want to do and why. But the ideal solution as explained in the answer would be a database structure where you could just query for those documenst you want to listen to and then just listen to that "filtered" list in witch only the docs you want to listen are in. With the `in` it's not possible because of the limitation of 10 and your requirement of 40-50 elements to filter to. – Tarik Huber Aug 05 '21 at 06:37
1

As you've discovered, Firestore's in operator only allows up to 10 entries in the array. I'm also guessing you've added the docID as a field in the document, since I don't believe 'docID references the actual documentid.

I would not take this approach, because of the 10-entry limitation. What I would do is, as the client is selecting documents to follow, set a field (same in each document) to a unique Id for the client, so your query completely avoids the limitation. You can allow an unlimited number of Client listeners (up to implementation limits of Firestore) if you add that client ID into an array (called something like "ListenerArray") [again, as the client is selecting them]. Your query would be more like:

docsRef.where('ListenerArray', 'array-contains', clientID).onSnapshot((doc) => {
   handleSnapshot(doc);
   })

array-contains checks a single value against all entries in a document array, without limit. Every client can mark any number of documents to subscribe to.

LeadDreamer
  • 3,303
  • 2
  • 15
  • 18
  • Hmmm. @TarikHuber, who makes an excellent point: "if you know the doc ids, just listen to them". But you're right to imagine that there's a reason the OP wants those particular docs that is *expressible in a query*. I don't like the idea of adding the doc id into the doc and then querying that. Might as well take the other answer. Instead I'd encourage the OP to understand *why* those docs and query for them based on domain specific properties. If the OP can't do that, then I'd go with the other answer, but I like your instinct here. – danh Aug 04 '21 at 22:18
  • @LeadDreamer Ya, it's too bad the "in" limitation of 10. I don't think the idea of adding a value for the "client" into the data and doing an "array-contains" would really work here either. The list of doc's I will be looking for is fairly dynamic. Basically, it's a database of airport weather. And I am dynamically generating a list of airports based on if it has a flight coming / going. I then use this list to pull out just the weather for the airports I am interested in vs. getting it all . In practicality, it won't be more than 30 or 40 airports. Are 30 or 40 listeners ok? – pilotGuy Aug 05 '21 at 00:00
  • @pilotGuy it's not really the number of documents at issue - you can establish a listener on 1000's, but note when you *start* the listener you will read *all* of them - it's number of clients listening. As I described, it will be *one* listener per client, listening to every document their clientID has been added to. – LeadDreamer Aug 05 '21 at 01:14
  • @danh if you "know the docIDs just listen to them" means you will have one listener PER DOCUMENT - a lot of round-trips. As to putting the docID's in the documents - it's the RECOMMENDED APPROACH if you are going to use docID's - you'll find querying on docID is difficult for a lot of reasons. ( see https://stackoverflow.com/a/58104104/2434784 ) – LeadDreamer Aug 05 '21 at 01:17
  • @pilotGuy, your comment begins to supply the semantics that will make this answer the right answer. The query plan is something like: given flights, "get" airports, and given airports, "listen" to weather. That plan needn't -- and probably shouldn't -- rely on doc IDs. Those are -- should be -- query-able properties of the docs. Don't subscribe to doc IDs, subscribe to queries. – danh Aug 05 '21 at 01:45
  • @LeadDreamer, I hope I've been clear that I agree with you that a query is superior to multiple listeners; I'm just resistant to the idea of forcing docs to contain their own IDs. I can see how inserting doc ids into docs is a recommended approach when querying for doc ids. I'd be just as readily convinced that wearing a helmet is the recommended approach when jumping off a bridge. – danh Aug 05 '21 at 01:55