checking if querysnapshot has made a connection to the firestore - firebase

When a certain document exists I want to go to another page then when a document does not exist. The code below does well when the app user has connection. However, when the connection to the internet is lost, the function will always return that it could not find the query. What I want to do is let the function give an error when it could not connect to the firestore so I can stay on the same page and try again.
Thank you in advance!
Future<bool> checkIfDocExists({String? id}) async {
var snapshot = await FirebaseFirestore.instance
.collection('rentals')
.where('DeviceID', isEqualTo: id)
.where('Status', isEqualTo: 0)
.get();
return (snapshot.docs.isNotEmpty);
}

In this case you should check device internet connection.
There is a package to help you to check internet status.
connectivity_plus => https://pub.dev/packages/connectivity_plus
connectivity => https://pub.dev/packages/connectivity
Code sample :
ConnectivityResult? _connectivityResult;
Future<void> _checkConnectivityState() async {
final ConnectivityResult result = await Connectivity().checkConnectivity();
if (result == ConnectivityResult.wifi) {
print('Connected to a Wi-Fi network');
} else if (result == ConnectivityResult.mobile) {
print('Connected to a mobile network');
} else {
print('Not connected to any network');
}
setState(() {
_connectivityResult = result;
});
}
You can check internet connection before read document from firestore.

If you want to make sure the document is read from the server, you can specify a source option for that:
...
.get(GetOptions(source: Source.server));
With this option the call will fail when it can't read the document from the server.
Also see the FlutterFire reference documentation for Source.

Related

How do I index queries in Firebase?

I'm trying to get documents that contain location fields that match with the user's location using:
getLocationListings(placemark) async {
setState(() {
isLoading = true;
});
QuerySnapshot snapshot = await FirebaseFirestore.instance
.collectionGroup("posts")
.where('location', isGreaterThanOrEqualTo: placemark.locality)
.get();
setState(() {
posts = snapshot.docs.map((doc) => Post.fromDocument(doc)).toList();
isLoading = false;
});
}
I'm getting the error:
Operation was rejected because the system is not in a state required for the operation's execution. If performing a query, ensure it has been indexed via the Firebase console.
Yet I have created indexes at the console as
How can I correct this?
Something might be wrong in the indexes you created for that collection group. I would recommend you to delete the index you created and run the function again, it's going to throw an error and if you were to check android device logs by executing
adb logcat
on the terminal you will see a message like this:
'FAILED_PRECONDITION: The query requires an index. You can create it here: https://console.firebase.google.com/v1/r/project/XXXXXXXXX/firestore/indexes?create_composite=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'.
Just click on the link and create the proposed index, this should fix the issue.

Admin access with flutter - hide and show widget and button based on User right firebase

I am working to build an admin access to a client. Among the visibility I need to constraint is the visibility of the button.
When changing access to user to admin, the button is not appearing back. The dependent boolean condition is mentioned below.
bool _show = false;
void showFloationButton() {
setState(() {
_show = true;
});
}
void hideFloationButton() {
setState(() {
_show = false;
});
}
void userAdminAccess() async {
FirebaseUser currentUser = await FirebaseAuth.instance.currentUser();
if ( currentUser != null) {
Firestore.instance
.collection('Users')
.where('isAdmin', isEqualTo: true);
} return showFloationButton();
}
Your code looks like it wants to perform a query, but it is not actually doing so. It's just building a Query object. You have to use get() to actually make that query happen, and await the response:
var querySnapshot = await Firestore.instance
.collection('Users')
.where('isAdmin', isEqualTo: true)
.get();
if (querySnapshot.size > 0) {
// there is at least one document returned by this query
}
else {
// there are not matching documents
}
I suggest learning more about how to perform queries in the documentation.
Note that what you're doing is potentially very expensive. It seems to me that you should probably get a single document for the user, identified by their UID, and look for a field within that document. Getting all admins could incur a lot of reads unnecessarily.

flutter firstWhere not responding (firestore)

I did a function a few months ago where my application is waiting for the user documents and responding accordingly. It was working like a charm until I optimized and updated the project to the last version.
If there is a user document, the stream yields the document and closes the stream.
If there is no user data in the cloud firestore, the stream yields null and awaits for the document to appear in the cloud.
// this function doesn't work properly and it should work but `firstWhere` is not
// listening to the stream unless there is a listener already which makes no sense
static Stream<DocumentSnapshot> get getUserDocumentWhenExists async* {
User user = FirebaseAuth.instance.currentUser;
if (user == null) throw 'No user is signed in';
FirebaseFirestore firebase = FirebaseFirestore.instance;
CollectionReference usersCollection = firebase.collection('users');
Stream<DocumentSnapshot> userDocumentStream = usersCollection.doc(user.uid).snapshots();
userDocumentStream.listen((event) {}); // <= this is here for the code to work
DocumentSnapshot userDocument = await userDocumentStream.first;
if (userDocument.exists == false) {
yield null;
yield await userDocumentStream.firstWhere((userDocument) {
// not beeing called without a previous listener
return userDocument.exists;
});
} else {
yield userDocument;
}
}
If you run this code without removing userDocumentStream.listen((event) {}) it will work without a problem as it did before the update.
My questions are:
Is this a bug?
Why is this happening? or did I just wrote something wrong?
Edit: I made a custom test without firebase and everything works fine. Just in this particular case firstWhere() is not listening to the stream
Edit2: after some more testing I discovered that any listener after userDocumentStream.first will not work. Now I'm more confused and I really need some help
I think after first() is called, the subscription is canceled even if in the first documentation it says otherwise:
"Internally the method cancels its subscription after the first element. This means that single-subscription (non-broadcast) streams are closed and cannot be reused after a call to this getter."
My solution:
Create a snapshots() stream for the first() and one for firstWhere()
final documentReference = usersCollection.doc(user.uid);
final userDocument = await documentReference.snapshots().first;
if (userDocument.exists == false) {
yield null;
yield await documentReference.snapshots().firstWhere((userDocument) {
return userDocument.exists;
});
} else {
yield userDocument;
}

How can I check the length of a firebase document using stream builder

In my flutter firebase app, I am able to get the length of a user's activity document in firebase using a query snapshot. However, I want the number of documents to update in real-time without the user needing to refresh the page. Can I do that by converting the codes below using stream builder to get the real-time length and how can I do that?
this is the code am using now which works perfectly well but doesn't update in real-time.
//this is the code I want to convert to stream
//builder.
static Future<int> numActivities(String userId)
async {
QuerySnapshot userActivitiesSnapshot = await
activitiesRef
.document(userId)
.collection('userActivities')
.where('seen', isEqualTo: '')
.getDocuments();
return userActivitiesSnapshot.documents.length;
}
You need to use the docs property, which "returns a List containing DocumentSnapshot classes", as follows:
return userActivitiesSnapshot.docs.length;
To get a stream of documents, you need to use the .snapshots() method which returns a Stream of QuerySnapshot instead of the .getDocuments() (deprecated in favor of .get()) method which returns a Future of QuerySnapshot.
Then you can map Stream<Snapshot> into a stream of the length of the snapshot's documents.
Your numActivities method should look like this:
static Stream<int> numActivities(String userId) {
return activitiesRef
.document(userId)
.collection('userActivities')
.where('seen', isEqualTo: '')
.snapshots()
.map((documentSnapshot) => documentSnapshot.docs.length);
}
Using this in your use case, you need to listen to the stream and update the _activityCount variable.
_setUpactivityCount() async {
final String currentUserId =
Provider.of<UserData>(context, listen: false).currentUserId;
DatabaseService.numActivities(currentUserId).listen((activityCount) {
if (mounted) {
setState(() {
_activityCount = activityCount;
});
}
});
}
Make sure you take care of _activityCount being null in it's initial state.

firestore query does not return documents inside flutter/dart mobile app, but works in javascript

Very strange behaviour I am experiencing with firestore.
Below dart code does not return the value
await Firestore.instance.collection('users')
.where("phoneNumber", isEqualTo: phoneNumber)
.getDocuments();
The javascript code from web returns the value
db.collection('users').where('phoneNumber', '==', 'xxxxxxxxxx').get().then((result) => {
console.log( result.docs.length )
}).catch((err) => {
console.log(err)
});
But I can clearly see the phone number does exist in the colection.
I just don't know if this is because of pending writes or cache. Where can I disable it if that is the case?
edit the code for phNumber
Future<User> getPhoneUser(String phoneNumber) async {
if (phoneNumber == 'xxxxxxxxxx') {
print('yes the phone number is same');
}
try {
QuerySnapshot qsnap = await usersRef
.where("phoneNumber", isEqualTo: phoneNumber)
.getDocuments();
int length = qsnap.documents.length;
if (length > 0) {
DocumentSnapshot doc = qsnap.documents[0];
doc.data['id'] = doc.documentID;
doc.data['createdAt'] = doc.data['createdAt'].toDate().toString();
doc.data['updatedAt'] = doc.data['updatedAt'].toDate().toString();
User user = User.fromJson(doc.data);
return user;
} else {
return null;
}
} catch (error) {
return null;
}
}
If you are running your flutter app on a simulator, sometimes the simulators go offline for some reason and you can no longer fetch data from the network.
If this happens, you can restart your simulator to bring the network connection back. I would suggest debugging with an actual physical device whenever possible.

Resources