In my flutter app, I am running a firestore query like this :
final userDoc = await _firestore.userDocument();
final name = nameStr.toUpperCase();
yield* userDoc.firestore
.collectionGroup('persons')
.where(
'name',
isGreaterThanOrEqualTo: name,
isLessThan: name.substring(0, name.length - 1) +
String.fromCharCode(
name.codeUnitAt(name.length - 1) + 1),
)
.snapshots()
.map(
(snapshot) => right<Failure, List<Person>>(
snapshot.docs
.map((doc) => Dto.fromFirestore(doc).toDomain())
.toList(),
),
)
.onErrorReturnWith((e) {
if (e is PlatformException && e.message.contains('PERMISSION_DENIED')) {
return ...;
} else {
print(e.toString());
return ...;
}
});
It shows the following error :
I/flutter (27416): [cloud_firestore/failed-precondition] 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.
Probably because of the where, I need to add index in console, so in the error message I am expecting an url to add index, but not getting it. I tried adb logcat, not even there.
In the documentation for collection group queries you will find at the bottom:
"Before using a collection group query, you must create an index that supports your collection group query. You can create an index through an error message, the console, or the Firebase CLI.
For the web and mobile SDKs, you must also create rules that allow your collection group queries."
So you will need to create security rules for your collection group and then, if you can't get the error message with adb logcat, you will need to manually create the index either through the Firebase console or the Firebase CLI.
You need to separate your where statements.
.collectionGroup('persons')
.where(
'name',
isGreaterThanOrEqualTo: name)
.where('name', isLessThan: name.substring(0, name.length - 1) +
String.fromCharCode(
name.codeUnitAt(name.length - 1) + 1),
)
Related
I'm trying to get one document by user id from firebase cloud firestore using flutter.
I tried firstly to fetch the data then added a condition to it, but i'm not able to display the data or even print it in the console!
Here is what i've tried so far:
database.dart:
Future<DocumentSnapshot?> getFileByUser(String userId) async {
return FirebaseFirestore.instance
.collection('cartesPro')
.where('cartUserId', isEqualTo: FirebaseAuth.instance.currentUser!.uid)
.get()
.then((value) {
value.docs.forEach((element) {
print(element.id);
});
});
}
ui page:
User? user = FirebaseAuth.instance.currentUser;
showFile() {
final files = DatabaseMethods().getFileByUser(user!.uid);
print(files);
}
and then made the call in a button so I can print the result only! it's returning the documents of the actual user, but I couldn't map the result in order to get the latest in timestamp order!
I appreciate any kind of help, thanks in advance!
If you want to get the most recent document for the user, you should order on the field that has the timestamp and the limit to a single result:
FirebaseFirestore.instance
.collection('cartesPro')
.where('cartUserId', isEqualTo: FirebaseAuth.instance.currentUser!.uid)
.orderBy('timestamp', descending: true)
.limit(1)
.get()
See the Firestore documentation on ordering and limiting data for more on this.
Im trying to fetch data using
Stream<List<User>> getUsers(User user) {
return _firebaseFirestore
.collection('users')
// .where('interestedIn', isEqualTo: _selectInterest(user))
.snapshots()
.map((snap) {
return snap.docs.map((doc) => User.fromSnapshot(doc)).toList();
});
}
The filter used in the where clause is as follows
_selectInterest(User user) {
if (user.interestPreference == null) {
return ['HIRING', 'WORK'];
}
return user.interestPreference;
}
In firebase I store interestPreference as an Array with 'HIRING' as the only element in the current user's data, when I try to fetch users with 'HIRING' in their interestedIn which is a string I dont get any data. But when I hardcode the where clause as
.where('interestedIn', isEqualTo: 'HIRING')
I get the data, Can anyone help me solve my dilemma?
From that last query, it sounds like the interestedIn field in your database is a single string value, like interestedIn: "HIRING".
Your current query returns documents where interestedIn is an array with exactly the two values you specify, so interestedIn: ['HIRING', 'WORK']
If you want to return all documents where interested in is either "HIRING" or "WORK", you can use an IN condition:
.where('interestedIn', whereIn: ['HIRING', 'WORK'])
Or with your helper function:
.where('interestedIn', whereIn: _selectInterest(user))
I have the following code in flutter:
QuerySnapshot querySnapshot =
await _firestore.collection("user1#gmail.com").get();
List Data = querySnapshot.docs.map((doc) => doc.data()).toList();
print("Length: ${Data.length}");
Here is my firestore database:
I get the following output:
I/flutter (11484): Length: 0
The Documents for each user email is variable, so I need the length of the documents. Also I need to get to the details of each document like content and title. How to do it? Thanks.
Could you try this:
int size = await FirebaseFirestore.instance.collection(collectionPath).get(GetOptions(source:Source.server))..size;
I will recommend finding a way to store the length of documents as a field in your Cloud Firestore database because calling the get function on a whole collection means filling up the mobile phone memory. (Say you have 500,000 users at least). This makes your app slow
You could have a field called count such that when you add a document, you can use the firebase transaction to update firebase.
For example:
// Create a reference to the document the transaction will use
DocumentReference documentReference = FirebaseFirestore.instance
.collection('users')
.doc(documentId);
return FirebaseFirestore.instance.runTransaction((transaction) async {
// Get the document
DocumentSnapshot snapshot = await transaction.get(documentReference);
if (!snapshot.exists) {
throw Exception("User does not exist!");
}
// Update the follower count based on the current count
// Note: this could be done without a transaction
// by updating the population using FieldValue.increment()
// Perform an update on the document
transaction.update(documentReference, {'followers': FieldValue.increment(1);});
// Return the new count
return newFollowerCount;
})
.then((value) => print("Follower count updated to $value"))
.catchError((error) => print("Failed to update user followers: $error"));
You can see more documentations here: FlutterFire
How do I make the following query in supabase on a stream listening for changes:
select * from public.messages where "to" IS NOT NULL;
From the documentation the closest, I could get was doing the filtering with an "equal to" expression. As captured below:
_messagesStream = supabase
.from('messages:to=eq.123')
.stream(['id'])
.order('created_at')
.execute()
.map((maps) => maps
.map((map) => Message.fromMap(map: map, myUserId: myUserId))
.toList());
But what I need is a query with "IS NOT NULL". A work around I found was to handle complex queries in a view, but the issue here is, I cannot listen for events on view.
Kindly assist.
I think it is not possible.
I checked supabase.dart and I can't find any solution on how to implement it.
But you can filter it on your side:
_messagesStream = supabase
.from('messages:to=eq.123')
.stream(['id'])
.order('created_at')
.execute()
.map((maps) => maps
.where((element) => element['to'] != null)
.map((map) => Message.fromMap(map: map, myUserId: myUserId))
.toList());
From Supabase docs / Filters / is()
const { data, error } = await supabase
.from('countries')
.select()
.is('name', null)
I'm trying to paginate comments. The first 10 comments is loading ok, but next ones (when query contains startAfterDocument) return error like:
Query(comments where movie_id == 1041047 order by -created, __name__) failed: Status{code=FAILED_PRECONDITION, description=The query requires an index. You can create it here: https://console.firebase.google.com/project/.......
But this index is already exist, I created it before. And if I follow the suggestion link Firebase Console tells me the same: this index is exist.
Future<List<DocumentSnapshot>> _loadPageFrom(
int index, DocumentSnapshot lastDoc) async {
Query query = Firestore.instance
.collection('comments')
.where('movie_id', isEqualTo: movieID)
.orderBy('created', descending: true);
if (lastDoc != null) query = query.startAfterDocument(lastDoc);
final snapshot = await query.limit(10).getDocuments();
return snapshot.documents;
}
What problem is here?
If you had recently deleted your index, you will need to wait a little bit until it's deleted from your project inside GCP, after that you will be able to create it again.