Flutter Multiple Firestore Queries - firebase

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();

Related

firebase realtime database not synced

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

Flutter Firestore - How to get data from a Document Reference in a Document Field?

I'm building a Self-learning app with differente questions types. Right now, one of the questions have a field containing a list of DocumentReferences:
In Flutter, I have the following code:
Query<Map<String, dynamic>> questionsRef = firestore
.collection('questions')
.where('lesson_id', isEqualTo: lessonId);
await questionsRef.get().then((snapshot) {
snapshot.docs.forEach((document) {
var questionTemp;
switch (document.data()['question_type']) {
....
case 'cards':
questionTemp = CardsQuestionModel.fromJson(document.data());
break;
....
}
questionTemp.id = document.id;
questions.add(questionTemp);
});
});
Now, with "questionTemp" I can access all the fields (lesson_id,options,question_type, etc..), but when it comes to the "cards" field, how Can I access the data from that document reference?
Is there a way to tell firestore.instance to get the data from those references automatically? Or do I need to make a new call for each one? and, if so, how can I do that?
Thank you for your support in advance!
Is there a way to tell firestore.instance to get the data from those
references automatically? Or do I need to make a new call for each
one?
No there isn't any way to get these documents automatically. You need to build, for each array element, the corresponding DocumentReference and fetch the document.
To build the reference, use the doc() method
DocumentReference docRef = FirebaseFirestore.instance.doc("cards/WzU...");
and then use the get() method on this DocumentReference.
docRef
.get()
.then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
print('Document exists on the database');
}
});
Concretely, you can loop over the cards Array and pass all the Futures returned by the get() method to the wait() method which "waits for multiple futures to complete and collects their results". See this SO answer for more details and also note that "the value of the returned future will be a list of all the values that were produced in the order that the futures are provided by iterating futures."

firebase index query implementation

Added a query mentioned below and also created the index in firebase but I don't know what happened since yesterday it is not showing data as per this query and if I remove this:- .where('age', isLessThanOrEqualTo:currentUser.ageRange['max']) from the below query then it shows the data other wise no data. Earlier this was working fine with no problem.
I have tried flutter clean but still no success, pls help me out as I want to implement this in project.
query() {
if (currentUser.showGender == 'everyone') {
return docRef
.where('age', isGreaterThanOrEqualTo: currentUser.ageRange['min'])
.where('age', isLessThanOrEqualTo:currentUser.ageRange['max'])
.orderBy('age', descending: false).limit(docLimit);
} else {
return docRef
.where('editInfo.userGender', isEqualTo: currentUser.showGender)
.where('age', isGreaterThanOrEqualTo:currentUser.ageRange['min'])
.where('age', isLessThanOrEqualTo: currentUser.ageRange['max'])
.orderBy('age', descending: false).limit(docLimit);
}
}
I believe the issue might be because of you're trying to run two range queries separately.
You may won't be able to do that as it's one of the limitation of querying.
You can try including both the comparisons in the single query like
.where("age",isGreater... : x, isLess..: y)
You can read about how querying works in firebase here:
https://firebase.google.com/docs/firestore/query-data/queries

Flutter Firebase - Search for documents which contain a string for

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.

How to check if an array in a firestore document is empty?

I'm building out an app in flutter and I want to run a query to determine if the array in my firestore document is empty. Is there a way to do this?
Here is a picture of my data structured in firestore.
I know there is an arrayContains method but I'm not sure on how to check for an empty array. Here is my current code.
_postsStream = await _firestore
.collectionGroup('posts')
.where('timestamp', isGreaterThanOrEqualTo: _start)
.where('timestamp', isLessThanOrEqualTo: _end)
.where('problems', arrayContains: )
.snapshots();
I left the arrayContains: intentionally empty for now. Please advise on how I would go about implementing this feature. Thanks in advance!
An empty array defaults to [] So this is possible by doing the following:
Do not use ' ' for the square brackets
final _database = Firestore.instance;
return _database
.collection('arrays')
.document(arrId)
.where('array', isEqualTo: [])
// .where('array', isNull: true) can be used to check if it's null
.snapshots()
.map(_itemListFromSnapshot);
You cannot do it in firestore currently.
What you can do is.
Create a separate property hasProblems which defaults to false.
If the user try to register a problem, then check the flag hasProblems.
If hasProblems==false, then toggle it to true and add the problem to the list.
else no need to toggle, just add the new problem to the list.
If problems are to be removed later on, then check for the list to get empty.
Once it is empty, then toggle hasProblems back to false.
This way you can achieve what you want-
postsStream = await _firestore
.collectionGroup('posts')
.where('timestamp', isGreaterThanOrEqualTo: _start)
.where('timestamp', isLessThanOrEqualTo: _end)
.where('hasProblems',isEqualsTo: false)
.snapshots();
Maybe you can have other better solutions, but this is the one that came in my mind.
You can follow the solution #mubin986 has given, but once the list gets bigger and bigger, it impacts performance.
Cheers, hope it helps.
There is no way to check with firestore query if an array is empty or not.
But, you can follow these steps:
Query the data with range filters:
_postsStream = await _firestore.collectionGroup('posts')
.where('timestamp', isGreaterThanOrEqualTo: _start)
.where('timestamp', isLessThanOrEqualTo: _end)
.snapshots();
After fetching the data, iterate over all the DocumentSnapshot and check if problems array is empty or not.

Resources