Query a Map containing an ID saved in Cloud Firestore with Dart/Flutter - flutter

How to get a Map stored in Cloud Firestore with Dart/Flutter ?
I tried this but it only works with Array :
Firestore.instance
.collection('posts')
.orderBy('createdAt', descending: true)
.where("userlist", arrayContains: userId)
.snapshots(),
here is the map stored in firebase

It doesn't really make sense for userlist to be an array here. Firestore doesn't let you query for values of maps inside an array. Just store it as a map. If userlist was just a map of uid/value pairs, you could query it like this using dot notation:
Firestore.instance
.collection('posts')
.orderBy('createdAt', descending: true)
.where('userlist.' + userId, isEqualTo: true)
.snapshots(),

Just adding to Doug Stevenson's answer, I had to use the key isGreaterThan: '' in order to not get an empty array.
Firestore.instance
.collection('posts')
.where('userlist.' + userId, isGreaterThan: '')
.snapshots(),

I don't recommend your way of data model. Because of some limitations as below:
You can only have 20000 fields in a firestore document (including array fields).
You can't assign security rules to each field. Security Rules is a thing that you have to think of.
You can't query them.
So, better I would recommend you to use documents for each user.

I've tried both Doug Stevenson's and Dan James's answers and was getting empty array as a result.
I've finally received the correct result by using the where clause with not equal to ''

Related

FirebaseException: Not able to query a collectionGroup

I am trying to do a pretty simple query in firebase for a collectionGroup. I only want to get all the products that are of the type "Restuarant". The code is below:
QuerySnapshot res = await FirebaseFirestore.instance
.collectionGroup('products')
.where("type", isEqualTo: "Restuarant")
.get();
It keeps throwing a FirebaseException as below:
I have added an exception in the Firebase indexes. It is a single field index.
What is the issue here? Why is this Exception occurring?
So I was able to get it working by adding a composite index. After adding the composite index, I was able to perform orderBy query too, using the rating field.
QuerySnapshot res = await FirebaseFirestore.instance
.collectionGroup('products')
.where("type", isEqualTo: "Restuarant")
.orderBy("rating", descending: true)
.get();

How can I filter from the map in the document?

How can I filter from the map in the document?
my query function;
ref
.where('tag_id', isEqualTo: item)
.where('likes', arrayContains: {
Get.find<AuthController>().getCurrentUser!.uid: true
})
.orderBy('created_date', descending: true)
.orderBy('like_count', descending: true)
.orderBy('comment_count', descending: true)
.limit(max.value)
.get();
I want to filter on 'likes' map. I tried to make an example in the code below, but no data is coming.
map in document
returning null
Your likes is not an array, so array-contains won't work on it.
What you're looking for is :
const uid = Get.find<AuthController>().getCurrentUser!.uid;
ref
.where('tag_id', isEqualTo: item)
.where('likes.$uid', isEqualTo: true)
For more on this dot notation, see the Firebase documentation on updating fields in nested objects.

Trying to order Firestore results in query

I have a query that I would like to order by a start date and filter by end date.
return FirebaseFirestore.instance
.collection("content")
.where("active", isEqualTo: true)
.where("end", isGreaterThanOrEqualTo: DateTime.now())
.orderBy("start", descending: true)
.snapshots();
Error:
The initial orderBy() field '[[FieldPath([start]), true]][0][0]' has to be the same as the where() field parameter 'FieldPath([end])' when an inequality operator is invoked.
If you include a filter with a range comparison (<, <=, >, >=), your first ordering must be on the same field
https://firebase.google.com/docs/firestore/query-data/order-limit-data#limitations
So you should go with
return FirebaseFirestore.instance
.collection("content")
.where("active", isEqualTo: true)
.where("end", isGreaterThanOrEqualTo: DateTime.now())
.orderBy("end", descending: true)
.orderBy("start", descending:true)
.snapshots();
You are getting the following error:
The initial orderBy() field '[[FieldPath([start]), true]][0][0]' has to be the same as the where() field parameter 'FieldPath([end])' when an inequality operator is invoked.
Because there is no way you can get data from Firestore without first sorting on the end field when using an inequality operator. So you need to reorder the results in your application code. So after calling:
.where("end", isGreaterThanOrEqualTo: DateTime.now())
It's mandatory to call:
.orderBy("end", descending:false)
So your query should look like this:
return FirebaseFirestore.instance
.collection("content")
.where("active", isEqualTo: true)
.where("end", isGreaterThanOrEqualTo: DateTime.now())
.orderBy("end", descending:false)
.orderBy("start", descending:true)
.snapshots();
Don't also forget to create an index in order to make this query work.

Deleting a Firestore entry based on FIFO

I'm trying to create a script that deletes a record from a Firestore collection using a FIFO (First In First Out approach).
So if there are three matching results in the collection, the script should take the first one added and just delete that one (leaving the remaining two). My code is:
_firestore
.collection('myCollection')
.where('uid',
isEqualTo: _auth.currentUser.uid)
.where('field',
isEqualTo: widget.field)
.orderBy('Posted', descending: false)
.limit(1)
.get()
.then((querySnapshot) {
querySnapshot.docs
.forEach((documentSnapshot) {
_firestore
.collection('myCollection')
.doc(documentSnapshot.id)
.delete();
});
});
(Just to note: 'Posted' is the date the entry was added) Unfortunately this doesn't work, and all three results remain in the collection.
If though I use this script instead, then all three results are removed from the collection:
_firestore
.collection('myCollection')
.where('uid',
isEqualTo: _auth.currentUser.uid)
.where('field',
isEqualTo: widget.field)
.get()
.then((querySnapshot) {
querySnapshot.docs
.forEach((documentSnapshot) {
_firestore
.collection('myCollection')
.doc(documentSnapshot.id)
.delete();
});
});
An example of an entry in my collection is as follows:
So I know the logic, connection, fields etc... are all correct, but why does the first example not work?
Have you check you logs? I am pretty sure that Firebase is throwing an error saying that your collection need indexes with a link.
Just follow the link and the instruction to build the indexes. Once complete you should be able to do what you are looking for.
More info about Indexes: https://firebase.google.com/docs/firestore/query-data/indexing
and Simple queries / Coumpound queries: https://firebase.google.com/docs/firestore/query-data/queries

Multiple Where Cases in a Flutter Stream Builder built from Firestore Collection

I can't find documentation or example how to use multiple where clauses in Flutter Stream Builder returned by Firestore Collection.
The bellow query works
Firestore
.instance
.collection (collectionName)
.where ("index", arrayContains: search)
.orderBy ('date', descending: true )
.snapshots()
but return zero if I add an additional where clause
Firestore
.instance
.collection (collectionName)
.where ("index", arrayContains: search)
.where ('allowed_roles', arrayContains: GlobalVars.userRole.toString() )
.orderBy ('date', descending: true )
.snapshots()
The compound query examples in Firebase documentation look pretty much as above but there is missing Flutter or Dart examples.
EDITED :
I have also tried the query build pattern as workaround but it doesn't work neither. Flutter really doesn't want the arrayContains clause more than once.
CollectionReference collectionRef = Firestore.instance.collection (collectionName);
Query p = collectionRef.where ('allowed_roles', arrayContains: "3");
Query q = p.where ('index', arrayContains: "Dan");
Stream s = q.snapshots();
What I am missing here is what solution should programmer use for this problem a logical AND is a pretty basic equation and it is unusual to stuck on this feature.
You can't have two arrayContains filters in a query:
.where ("index", arrayContains: search)
.where ('allowed_roles', arrayContains: GlobalVars.userRole.toString() )
According to the documentation, only one arrayContains is supported at a time. This is a limitation of Firestore and can't be changed. The query is certainly generating an error - you should add code to check for errors instead of blindly assuming that it succeeds.
As brought up in the comments Firebase doesn't take more than one arrayContains clause .
The only solution for my case is to hooking a conditional statement for allow_roles array in my activities :
if( document['allowed_roles'].contains( GlobalVars.userRole ))