Can the Date in a firestore query (onsnapshot) be kept current - firebase

In my web app I fire off a query to gather all recent messages for a user and then use an onsnapshot to show these messages in a feed. In my app some messages get posted to the future so I only want messages from now or earlier in the feed.
var query = firebase.firestore()
.collection('messages')
.where('owner','==',userID)
.where('timestamp','<',new Date())
.orderBy('timestamp', 'desc')
.limit(25);
The user can then create new messages and I want those added to the feed displayed in the app. After adding a new message do I have to cancel the onSnapshot listener and execute a new query with an updated current Date? Or is there a way for this query to update the time lookup so that the onSnapshot is always getting newly posted messages?

If you want to change any of the query parameters, you need to build a new Query object with the new values and add a snapshot listener to it..

Related

Firestore snapshot - are dynamic queries possible?

I have two listeners - one for the user's profile and one for the rooms the user is in; the uids of the rooms are stored in an array on the profile, i.e. the query for the second listener depends on data from the first.
It looks like this (simplified):
// profile listener
onSnapshot(profileRef, (snapshot) => setProfile(snapshot.doc.data())
// rooms listener
const roomsQuery = query(
collection(db, "rooms")
where("uid", "in", profile.roomsList)
)
onSnapshot(roomsQuery, (snapshot) => setRooms(snapshot.docs)
When the user is added to a new room, the profile updates with the new roomsList. But the rooms snapshot doesn't update - presumably because the query can't be updated dynamically.
Question
So, is there a way of updating the listener's query (i.e. keeping the same listener), or do I have to unsubscribe from the existing listener and re-subscribe with the new query every time profile is updated?
Versions
Using the new V9 of the Javascript sdk
Firestore queries are immutable, so there's no way to change the condition once the query has been created. You'll indeed have to attach a listener to a new query to get the updates roomsList. If you enable offline persistence though, the overlapping documents between the queries will be read from the local cache.
Also see: How to constantly update query for Firebase Realtime Database with LiveData and ViewModel in Android

How does Firestore document snapshot work?

when a new document is added, snapshot fetches all the documents including the new ones or only the newly added ones ? If it fetches all the documents every time then it will add to the billing cost. How to get around this problem ?
StreamBuilder(
stream:Firestore.instance
.collection('chat')
.orderBy('timeStamp', descending: true).snapshots(),
builder: (context, streamSnapshot) {}
);
While your snapshots() listener stays active, the server actively monitors for changes that are relevant to your listener. When there are such changes it only sends you new documents, or documents that were changed, to your client. The client then merges those updates with its local data, and presents you with a new complete QuerySnapshot.
According to the official doc : Here
There are two ways to retrieve data stored in Cloud Firestore. Either of these methods can be used with documents, collections of documents, or the results of queries:
Call a method to get the data.
Set a listener to receive data-change events.
When you set a listener, Cloud Firestore sends your listener an initial snapshot of the data, and then another snapshot each time the document changes.
You can get an array of the document snapshots by using the docs property of a QuerySnapshot. After that you'll have to loop through getting the data of the doc snapshots looking for your doc.
OR if you don't actually need the full QuerySnapshot, you can apply the filter using the where function before calling get on the query object
These are the most efficient way to get documents.

How to properly update a Firestore query snapshot of an active stream?

I have a flutter app that searches for people on Firestore database based on different criteria such as city, country, region, etc. The app has the criteria as user-input that can be chosen then applied with a click of a button. When the button is clicked, the function below is called:
CollectionReference collectionReference = Firestore.instance.collection("profiles");
void getResults() {
// getQuery is a function that adds 'where' statements
// (e.g., .where("city", isEqualTo: "Paris);
Query query = getQuery(collectionReference, filters);
Stream<QuerySnapshot> snapshots = query.snapshots();
snapshots.map((docs) => docs.documents).listen((onData){
myStreamController.add(onData);
}
}
With the code above, a new query is created even if the existing stream contains all the data that is needed. For example, the user first retrieve all people from France first, then retrieves all the people from Paris only by updating the filter.
Since the existing stream already have all people from Paris, is it possible to dynamically update the query without creating a new stream/query?
What I'm trying to achieve here is that I want Firestore to take advantage the cache instead of retrieving all the documents again.
Firestore doesn't support dynamically changing the parameters of an active query. If you want to change the filters or ordering of an active query, you will have to stop the first query, create a new Query object, then execute the new query.

Firestore, fetch only those documents from a collection which are not present in client cache

I am implementing a one-to-one chat app using firestore in which there is a collection named chat such that each document of a collection is a different thread.
When the user opens the app, the screen should display all threads/conversations of that user including those which have new messages (just like in whatsapp). Obviously one method is to fetch all documents from the chat collection which are associated with this user.
However it seems a very costly operation, as the user might have only few updated threads (threads with new messages), but I have to fetch all the threads.
Is there an optimized and less costly method of doing the same where only those threads are fetched which have new messages or more precisely threads which are not present in the user's device cache (either newly created or modified threads).
Each document in the chat collection have these fields:
senderID: (id of the user who have initiated the thread/conversation)
receiverID: (id of the other user in the conversation)
messages: [],
lastMsgTime: (timestamp of last message in this thread)
Currently to load all threads of a certain user, I am applying the following query:
const userID = firebase.auth().currentUser.uid
firebase.firestore().collection('chat').where('senderId', '==', userID)
firebase.firestore().collection('chat').where('receiverId', '==', userID)
and finally I am merging the docs returned by these two queries in an array to render in a flatlist.
In order to know whether a specific thread/document has been updated, the server will have to read that document, which is the charged operation that you're trying to avoid.
The only common way around this is to have the client track when it was last online, and then do a query for documents that were modified since that time. But if you want to show both existing and new documents, this would have to be a separate query, which means that it'd end up in a separate area of the cache. So in that case you'll have to set up your own offline storage on top of Firestore's, which is more work than I'm typically willing to do.

Flutter Firestore where clause using map

When a new activity is posted i add a new post document into the collection.
Inside this document i have a map where users add confirmation to the event marking it as true and adding his own id.
var snap = await Firestore.instance
.collection('user_posts')
.where("confirmations.${user.id}",isEqualTo: true)
.getDocuments();
With this snippet i'm able to get all the posts confirmed by the user. The issue here is to get this a index is required to perform this query. And this index can't be generic. I can't create a index for each user.
Some idea of how to get it?
Thanks!!
You'll want to turn the confirmations field into an array, and use the (relatively recent) array-contains and arrayUnion operations.
The equivalent query with an array like that would become:
var snap = await Firestore.instance
.collection('user_posts')
.where("confirmations", arrayContains: user.id)
.getDocuments();
And this way you only need an index on confirmations, which is added automatically.
For more on these see:
the blog post introducing these operations
the documentation on updating arrays
the documentation on array membership queries

Resources