I am testing my app before release. I have one physical device on which I tested the offline capability on Saturday. On Sunday I added two more results using another device and the released app.
When I know read the data from firebase I only get the cached data on the first device. How can I enforce fetching the data from the online database?
I have tried with keepSynced(true), but I still get the same results. This is how I try and read the data:
await FirebaseDatabase.instance
.ref()
.child(usersKey)
.child(id5)
.ref
.keepSynced(true);
final userData5 = await FirebaseDatabase.instance
.ref()
.child(usersKey)
.child(id5)
.get();
userData5 contains 249 entries compared to 251 online. The diff of two comes from the two results added on Sunday.
How can I make sure to get the correct data?
I have also tried this now:
await FirebaseDatabase.instance
.ref()
.child(usersKey)
.child(id5)
.ref
.keepSynced(true);
var userData5 = await FirebaseDatabase.instance
.ref()
.child(usersKey)
.child(id5)
.get();
await userData5.child(idKey).ref.set(user.uid); <- Gets stuck
userData5 = await FirebaseDatabase.instance.ref().child(usersKey).child(id5).get();
The idea is to update the value of the database (with the same as before) to trigger a synchronisation. I have seen that on other places. But when I try to set the data it just stops. Nothing happens and I don't get to the last userData5 = await FirebaseDatabase.instance.ref().child(usersKey).child(id5).get();
Seems to be a similar solution here: https://medium.com/#naturallam/firebase-data-out-of-sync-during-initial-fetch-6e20b7a7c7b9
Related
my question is very simple but it mean a lot to me , i have more than 4 listen method in my flutter app which i can't use .cancle() to them since they are so important to keep in listen as long as user is active ,
Now my question is : let's say the app has thousands of active users monthly .. does it will effect of response performance of Firestore with these 4 listens methods for thousands of monthly active users ?
my listens methods are similar like this kind of data size .. most of them are moving data FROM/TO another collection's
FirebaseFirestore.instance.collection("users").doc(currentUser.uid).collection("handleCountM").where("new", isEqualTo: true).snapshots();
.listen((value){
value.docs.forEach((val) async {
String textMessage = await val.get("textMessage");
String image1 = await val.get("image1");
var timestamp = await val.get("timestamp");
String messageTime = await val.get("messageTime");
String name = await val.get("name");
String bio = await val.get("bio");
String senderUid = await val.get("senderUid");
String receiverUid = await val.get("receiverUid");
String notificationId = await val.get("notificationId");
final DocumentSnapshot countM2Id = await FirebaseFirestore.instance.collection("users").doc(currentUser.uid).collection("messages").doc(val.id).get();
if(countM2Id.exists ) {
int countM2 = await countM2Id.get("countM2");
final QuerySnapshot<Map<String, dynamic>> lengthId = await FirebaseFirestore.instance.collection("users").doc(currentUser.uid).collection("chats1").doc(val.id+currentUser.uid).collection("chats2").get();
await FirebaseFirestore.instance.collection("users").doc(currentUser.uid).collection("messages").doc(val.get("senderUid")).update({
"textMessage": textMessage,
"image1": image1,
"timestamp": timestamp,
"messageTime": messageTime,
"name": name,
"bio": bio,
"senderUid": senderUid,
"receiverUid": receiverUid,
"countM2": countM2,
"countM": lengthId.docs.length - countM2,
"notificationId": notificationId,
});
also i have read in firestore docs best performance section that should put under 100 listen snapshot methods fo each user . does it mean in my case no worries ? or they mean something is difference of my understanding .
thanks in advance
You're probably safe. It's really hard to have low performance on Firestore.
As far as I know, when it comes to performance and even costs the you only thing you need to worry is about how much data you're getting each time. It's easier to have performance issues with network (when you grab too much data in one time) so don't make your documents too big and don't grab too many documents at once that you may not need.
Also, setting up some listeners per user isn't a big deal either. Just be aware about how often you'll get charged for new reads when they are active if the data they're listening changes too often.
For instance, if the data on those collections are changing several times and you have thousands of users listening to the same collection queries, you may be charged for a lot of new reads every time there's a new value.
FirebaseFirestore.instance
.collection(
'chats/${site}/conversations/${room.id}/messages')
.orderBy('createdAt', descending: true)
.where("createdAt", isGreaterThan: dateTime )
.snapshots()
.map(
(snapshot) {
So, On the first document that inserted to the firestore, the I get i a snapshot. On the second, the stream return the first and the second,
So the i get -
(Doc A)
(Doc A,Doc B)
(Doc A, Doc B, Doc C)
And so on. Is there a way to get:
(Doc A)
(Doc B)
(Doc C)
?
I reviewed your snippet and it appears you are using a Stream from the snapshot() method of a CollectionReference type. According to the documentation, this will stream events as they happen in Firestore. You mentioned that with each document inserted in Firestore, you also started getting the previous documents that were inserted before, instead of getting only the one which was just inserted (the latest). This might be related to the dateTime variable you are using to filter documents. Since you are using a greater than comparison, any documents created after the time set in the dateTime will be returned from the query. This could explain why your query returns additional documents each time a new one is added with a timestamp after the dateTime variable.
If you would like to get only the latest document added to the database each time, you can make use of a query limiter. I tested the limitToLast method to get only the latest document added and it appears to work in my testing. This method returns the very last document in a query, and in order for this to be the newest you would have to invert the process to order by ascending (oldest first) so that the newest document is at the bottom:
FirebaseFirestore firebase = FirebaseFirestore.instance;
firebase
.collection('users')
.orderBy('createdAt', descending: false) // orders by ascending order, latest document is the last
.limitToLast(1) // gets the last document, you can set how many docs to get
.get()
.then((QuerySnapshot snapshot) {
if (snapshot != null) {
// Data is available
snapshot.docs.forEach((doc) {
print(doc['firstName']);
});
} else {
print("No data found");
}
}
for everyone who reach this issue on 2022, the solution is rather simple.
You can stay with the same query but check the doc changes:
snapshot.docChanges.forEach((docChange) {
final data = docChange.doc.data() as Map;
LimitToLast won't solve your problem if the internet connection was down for a few moments and multiple updates arrived, but docChanges is all the changes since the last snapshot.
Note: You need to ignore the first time because it will return all the docs on the collection at the first time.
I have a question regarding a request to retrieve data from Google Cloud Firestore with specific parameters in my Flutter project.
I use the following code to check if a string in Firebase equals to a search query performed by a user:
var snapshot = await firestoreInstance.collection('categories/subcategory/items')
.where("parameter", isEqualTo: searchQuery).get()
This works if the user types exactly the name of the parameter stored in Firestore. But what I want is that it also works if only part of the searchQuery string is stored in the Firestore parameter.
I found a solution on https://medium.com/flutterdevs/implement-searching-with-firebase-firestore-flutter-de7ebd53c8c9 for this. In the article an array is created with all possibile searches for the parameter. But I think that is a bit complex and you have to generate a lot of new data in Firestore just to search for the article.
Is there a way to do this in an easier way so that you can use an operator as "contains" instead of "isEqualTo" in Flutter with Firebase for the request?
var snapshot = await firestoreInstance
.collection('categories/subcategory/items')
.where(
'parameter',
isGreaterThanOrEqualTo: searchQuery,
isLessThan: searchQuery + 'z'
)
.get();
Try this:
var snapshot = await firestoreInstance
.collection('categories/subcategory/items')
.where(
'parameter',
isGreaterThanOrEqualTo: searchQuery,
isLessThan: searchQuery.substring(0, searchQuery.length - 1) +
String.fromCharCode(searchQuery.codeUnitAt(searchQuery.length - 1) + 1),
)
.get();
I based the variable names on your example.
My database looks something like this:
Now as I start adding more and more data I will be getting variety of users. I want to extract data from one user based on their user ID. I tried using these codes but none of them worked. I am getting data in bulk of all the users but I just want one of them. Here's my attempt:
final data=await _collection.collection('UserDetails').getDocuments();
//print(user.uid);
DocumentReference ref = await _collection.collection('UserDetails').document(user.uid);
var lister=await ref.collection('Name');
print(lister);
This is the code for getting all their data:
for(var msgs in data.documents)
{
print(msgs.data);
}
I want a function or anything which could return data in this way:
function.giveUserID('uid').giveDataYouwanttoExtract('Attribute')
I can filter out using string conditions from all the data I am getting but as the database rises it will have to extract tons of data at once which will affect the performance and so I want to do this in this way. Please let me know if there's any way to just extract data of one user based on their uid or email or anything.
You can use queries. The code below returns all the users where name is equals to the Jack.
await _db.collection("UserDetails")
.where("Name", isEqualTo: "Jack")
.getDocuments()
.then((QuerySnapshot snapshot){
snapshot.documents.forEach((DocumentSnapshot documentSnapshot){
print(documentSnapshot.data);
});
});
I am trying to make multiple queries to Firestore and merge the results into one stream like here. I tried using StreamGroup.merge() but it's only returning the results of one stream. I noticed that it does actually get data for all the streams but only returns one when everything completes. Here is what I did:
Stream getStream(){
List<Stream> streams = [];
streams.add(Firestore.instance.collection(Constants.REQUESTS_NODE).
where("municipality",isEqualTo: "City of Johannesburg Metropolitan").
where("service_id",isEqualTo: 2).
snapshots());
streams.add(Firestore.instance.collection(Constants.REQUESTS_NODE).
where("municipality",isEqualTo: "Lesedi Local").where("service_id",isEqualTo: 2).
snapshots());
return StreamGroup.merge(streams);
}
What am I missing and doing wrong? The reason I'm doing this is to compensate for Firestore's lack of OR operator.
I found this online, hope it helps:
`import 'package:async/async.dart';
Stream<DocumentSnapshot> stream1 = firestore.document('/path1').snapshots();
Stream<DocumentSnapshot> stream2 = firestore.document('/path2').snapshots();
StreamZip bothStreams = StreamZip([stream1, stream2]);
// To use stream
bothStreams.listen((snaps) {
DocumentSnapshot snapshot1 = snaps[0];
DocumentSnapshot snapshot2 = snaps[1];
// ...
});`
You can use whereIn condition, it's a List<dynamic>, that's work with me!
For example:
Firestore db = Firestore.instance;
db.collection
.where("status", whereIn: ["available", "unavailable", "busy"])
.getDocuments();