简体   繁体   中英

How to get a DocumentSnapshot for a specific document out of a QuerySnapshot?

To make things simple, let's say I've got two screens:

  • StoriesListScreen
  • StoryDetailsScreen

To populate StoriesListScreen I fetch some data from Firestore, using a Stream :

Stream<QuerySnapshot> getFirstTenStories() {
    return _firestore.collection('stories').limit(10).snapshots();
}

I then use this Stream in a StreamBuilder in StoriesListScreen and map the documents it contains to some Story objects. I then use a ListView.builder which creates some StoriesListTile objects taking a Story object as a parameter so that they can render each object in the list.

So all is well...

But when the user clicks on a StoriesListTile , I would like to open the StoryDetailsScreen and show the details of that specific Story object.

Since the Story object exists at this point and has already been passed in the StoriesListTile object, I can easily pass in this Story object to the StoryDetailsScreen :

 Navigator.of(context).push(MaterialPageRoute(builder: (context) => StoryDetailsScreen(_story));

So it works fine, but...

I would like to be able to listen to any change in the data used to create the Story object.

At the moment if my data change in Firestore then my list in StoriesListScreen will automatically be updated because it uses a Stream<QuerySnapshot> .

I would like to do the same in StoryDetailsScreen but what I pass to the StoryDetailsScreen screen is not a Stream , it is a Story object that will not be updated.

One solution could be to fetch this story data from Firestore and use the Stream<DocumentSnapshot> in a StreamBuilder in StoryDetailsScreen , so it will be automatically updated if the data changes. But that would mean wasting another Firestore read because I already have this data.

So how can I pass in a Stream<DocumentSnapshot> for a specific Document to my StoryDetailsScreen ? Is it possible to extract it from the Stream<QuerySnapshot> I already have?

I really like this question, you are making me reconsider how I've written my app and I'm now wondering if there is a better way now too. Thanks for that!

I think that fundamentally this problem is about separating out the business logic (the data in the streams) from the UI (which page is currently loaded).

I'd look at using Provider and create a service that serves up a stream that any of the widgets in the app can access. This way you have a single service that is listening for changes, updating the data and everything else in the app listens to that stream.

Is this what you were looking for?

Edit

Do you get charged for a stream that is listening for changes to the database?

The answer is, 'It depends' This is from the Cloud Fire-Store Billing documentation .

Listening to query results

Cloud Firestore allows you to listen to the results of a query and get realtime updates when the query results change.

When you listen to the results of a query, you are charged for a read each time a document in the result set is added or updated. You are also charged for a read when a document is removed from the result set because the document has changed. (In contrast, when a document is deleted, you are not charged for a read.)

Also, if the listener is disconnected for more than 30 minutes (for example, if the user goes offline), you will be charged for reads as if you had issued a brand-new query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM