Cloud Firestore OR query - firebase

How do I fetch multiple documents from firebase? I want to fetch all of the documents that are in a list.
I can only run the below query if instead of a list I pass it a single item for the owner field since isMemberOf is not a real operator. I put it there as something that I imagine it might look like.
Right now I can only pass a single value and use isEqualTo: instead of my made up operator.
How do I do this?
Stream<List<Event>> subscribeToEventsByDates(
List<String> users, DateTime start, DateTime end) {
return Firestore.instance
.collection('events')
----> SELECT * (all that match) <------- doesn't exist? How to do this?
.where('owner', isMemberOf: users)
.where('start', isGreaterThanOrEqualTo: start)
.where('start', isLessThanOrEqualTo: end)
.snapshots()
.map((snapshot) => snapshot.documents
.map((event) => Event.fromJson(event.data))
.toList());
}

If you want to pass an array of strings to a filter to match any one of them for a given field, that's called an "in" query.
The API documentation for where() suggsets that you should use "whereIn" for that.
.where('owner', whereIn: users)
From the documentation on in queries:
Use the in operator to combine up to 10 equality (==) clauses on the same field with a logical OR.

Related

how to query (filter) documents from firebase to flutter app based on a value nested in a List of Maps?

im trying to get documents from my 'Patients' Collection which contain an array of maps 'Appointments' based on the value of 'translator' key as shown here:
here is how im trying to query the documents but i guess im having a syntax error
static Stream<QuerySnapshot> getSpecificUserAppointments(String translatorName) {
return FirebaseFirestore.instance
.collection('Patients')
.where('appointments', arrayContains: translatorName)
.snapshots();
}
i also tried to filter this way
.where('appointments.translator', arrayContains: translatorName),
.where('appointments.translator', isEqualto: translatorName)
still not getting results
any help would be appreciated
The arrayContains operator checks whether the exact, complete item you specify exists in the array. So your check would only work if the appointments array contained an entry that has a single string as its value with translatorName.
If you want to check whether a certain name exists, add an additional array field to your document with translatorNames, where you keep just the (unique) names of the translators in the document. Then you can use that field to query:
return FirebaseFirestore.instance
.collection('Patients')
.where('translatorNames', arrayContains: translatorName)
.snapshots();

Firebase check if item is not in array in Flutter

I want to check in my Flutter app if an item is not in an array. If it is in it I want to sort it out, if not I want to take it.
There is an arrayContains function for the reverse function, but I couldn't find an arrayContainsNot function or something. How can I solve this?
I want to do it like this:
await FirebaseFirestore.instance
.collection("someCollection")
.where("someArray", arrayContainsNot: "someItem")
.get();
You can use the not-in operator.
A not-in query returns documents where the given field exists, is not
null, and does not match any of the comparison values.
So your code becomes:
await FirebaseFirestore.instance
.collection("someCollection")
.where("someArray", whereNotIn: ["someItem"])
.get();
Note that it supports up to 10 comparison values which have to be passed in a list to the whereNotIn property.

Cloud Firestore inequality operator exception flutter

while i have been using cloud firestore in my flutter app, strange exception occured.
EDITED
this is my code:
Stream<List<Product>> productsStream(int id) async* {
final k = _db
.collection('products')
.where('category_id', isEqualTo: id)
.where('stock', isGreaterThanOrEqualTo: 1)
.orderBy('order')
.snapshots();
yield* k.map((event) => event.docs
.map((e) => Product.fromJson(
e.data(),
))
.toList());
Here what i would like to achieve is to check for a product wether it is in stock and then to order products in an ascending order by order field in my products collection.
But i am receiving this strange error:
Exception:
'package:cloud_firestore/src/query.dart': Failed assertion: line 421 pos 16: 'field == orders[0][0]': The initial orderBy() field '[[FieldPath([order]), false]][0][0]' has to be the same as the where() field parameter 'FieldPath([stock])' when an inequality operator is invoked.
What might be solution?
This is explained in the ordering limitations documentation:
If you include a filter with a range comparison (<, <=, >, >=), your first ordering must be on the same field
So I suspect you should have:
.where('category_id', isEqualTo: id)
.where('stock', isGreaterThanOrEqualTo: 1)
.orderBy('stock')
.orderBy('order')
Obviously that means it's no longer primarily ordered by order. You'd need to do local sorting if that's a problem - in which case you may find you don't want to order server-side at all.
Although "not equal to" filters aren't mentioned in the documentation, it sounds like they also count as range comparisons in terms of prohibiting filtering.
So basically, I would suggest you either need to filter locally on stock, or you need to order locally on order - you can't do both in the same Firestore query at the moment. Note that this server-side limitation is something that could change in the future (either for all range comparisons, or possibly just to allow "not equal to") so it may be worth retesting periodically.
You may need to do these two things. (it worked for me as shown in the example down below).
1 - Add an index for stock as Ascending in the console. This index should be in ascending.
2 - You must query based on that index.. So, as opposed to doing
...
.where('stock', isGreaterThanOrEqualTo: 1)
...
You should be doing
...
.orderBy('stock', descending: false)
.where('stock', isGreaterThanOrEqualTo: 1)
...
This applies to all other composite indexes that have equality checks. So you may need to do that for category_id
Also, here's my code for example
For context. I'm displaying a chat list, where the number of messages are greater than 0, and of-course, where the current user is a participant
1 - In GCP https://console.cloud.google.com/firestore/indexes/composite?project=**your-project-name**
I added the required index as such
Composite index setup
2 - Then finally, in my flutter code
static Future<QuerySnapshot> getUsersChatsList(String userId,
{DocumentSnapshot? startAfterDoc, int limit = 10}) =>_chatsRef
.where('participants_ids', arrayContains: userId)
.orderBy('message_count', descending: false)
.where('message_count', isNotEqualTo: 0)
.orderBy('last_message_created_at', descending: true)
.limit(limit)
.get();
Ignore the limit & startAfterDoc as that was done for pagination
NOTICE that I had to manually order message_count in ASC before checking the condition.
And finally, of course, they're sorted in DESC in time.
You should make sure that you are ordering with the same constraint as your where like this:
getInventory() async {
String value = user.uid;
return inventoryFirebaseReference
.orderBy('availableStock')
.where('userFirebaseId', isEqualTo: value)
.orderBy('availableStock')
.where('availableStock', isGreaterThan: 0)
.snapshots()
.listen((event) {
chargeProducts = false;
final _documentList = event.docs;
//print(_documentList.length);
_documentList.map((e) => {});
List<ProductMoof> listProductsProv = _documentList.map((doc) {
ProductMoof inventoryItemProv =
ProductMoof.fromMap(doc.data() as Map<String, dynamic>);
inventoryItemProv.firebaseId = doc.id;
return inventoryItemProv;
}).toList();
listInventory = listProductsProv;
notifyListeners();
print('Update gotten from Menu');
});
}

Unable to get the documents after creating a query index

Code:
var querySnapshot = await Firestore //
.instance
.collection('collection')
.where('name', isEqualTo: ['foo'])
.orderBy('time')
.limit(1)
.getDocuments();
print('${querySnapshot.documents}'); // prints []
It returns empty List.
Database structure:
Index built
Indexing isn't an issue here. Given the query and document you're showing, I'd always expect it to return no results. You're using an array-contains type query on a field that isn't an array. Your name field is a string, and strings can't be matched by array-contains queries.
If you intended for name to be an array, you'll need to modify the document so that it is actually an array with the string "foo" in it.

Flutter/Firebase get documents by list of IDs using .get()

This is a followup to Flutter Firebase get documents by array of IDs.
How would I get a Query of documents from a collection using a list of IDs? Let's says I have the following:
List<String> someList = ['abc123', 'def456', 'hij789']; // Need to query for these documentIDs
I'm using FieldPath.documentId() which works, but limits the query to 10.
Query query = Firestore.instance
.collection(APIPath.products())
.where(FieldPath.documentId(), whereIn: someList);
I would normally pass query to a function of mine that would return a Stream<List<Product>> as seen below.
return _service.queryStream(
query: query,
path: APIPath.products(),
builder: (data) => Product.fromMap(data),
);
I know get() is a better option, but not sure what the code would look like if I wanted to return a Stream<List<Product>>.

Resources