Get non empty Sub Collections in Firestore using Query class - firebase

I am trying to get non empty Rooms from Buildings Collection from Firebase Firestore ( Using Flutter Framework):
Query _queryRef = FirebaseFirestore.instance
.collection('Buildings')
.where("isActive", isEqualTo: true)
.where("Rooms", isNotEqualTo : null);
But I am not getting any collections Even though there are few Rooms sub collection records exist in Buildings.
Adding Screenshot for reference-

Queries in Firestore work on a single collection, or on a group of collections of the same name. There is no way to query your Buildings documents on the existence of or values in their Rooms subcollection.
The typical workaround is to store a RoomCount field in each Buildings document, and keep that up to date as you add/remove rooms. With that in place you can query:
FirebaseFirestore.instance
.collection('Buildings')
.where("isActive", isEqualTo: true)
.where("RoomCount", isGreaterThan: 0);

Append .get() at the end of your query. Here you can read more about most common use cases of working with firebase via flutter.

Related

How to make a query from a nested collection in firestore using flutter

I have a nested collection in firestore that I want to make a query from it.
As you can see the first collection called 'businessUsers' and the nested one called 'campaigns',
If I make a query for a field in the 'businessUsers' it's working OK:
return FirebaseFirestore.instance.collection("businessUsers").where('xxx',
isEqualTo:filterBusinessResult ).snapshots().map(_businessListFromSnapshot);
but how can I make a query to 'campaigns' collection field?
I tried
return FirebaseFirestore.instance.collection("businessUsers").doc().collection("campaigns").where('campaignCategory', isEqualTo:filterBusinessResult ).snapshots()
.map(_businessListFromSnapshot);
but it wont work.
Its important to note, that I need all the data with 'campaignCategory' == filterBusinessResult
any idea?
It depends on whether you want to query a specific user's campaigns, or the campaigns of all users together.
If you want to query the campaigns of a specific user, you need to query under their document:
FirebaseFirestore.instance
.collection("businessUsers").doc("your user ID").
.collection("campaigns")
.where('campaignCategory', isEqualTo:filterBusinessResult)
So you have to know the ID of the businessUsers document here.
If you want to query across all campaigns subcollections are once, that is known as a collection group query and would look like this:
FirebaseFirestore.instance
.collectionGroup("campaigns")
.where('campaignCategory', isEqualTo:filterBusinessResult)
The results are going to documents from the campaigns collection only, but you can look up the parent document reference for each DocumentSnapshot with docSnapshot.reference.parent.parent.
When querying something, .doc() requires the id of the document you're trying to get. So it's failing because it doesn't know which document in the businessUsers collection you're trying to fetch a subcollection on. You probably want to use a .collectionGroup() query here. They let you query all subcollections at once (see documentation here). With FlutterFire specifically, it's going to be something like:
var snapshots = FirebaseFirestore.instance.collectionGroup("campaigns")
.where("campaignCategory", isEqualTo: filterBusinessResult)
.snapshots();

Flutter Firebase: Retrieve a list of documents, limited to IDs in an array?

I'm working on a Flutter app where each user can create projects, and share projects with other users. I've created a 'shares' collection, where each user's ID is a document, and within that document, all project IDs that have been shared with that user are collected like so, with a boolean that represents whether or not the share has been accepted yet:
Next, I created a collection of the projects themselves, like so:
Now, I'd like to query the 'projects' collection and return only the projects that are in a given user's 'shares' list. First off, how can I get each document in the share list's ID? And secondly, is it possible to compare that ID to the contents of a List using a .where() clause?
I've been trying something like this, but to no avail:
Stream<List<Map<String, dynamic>>> getListOfProjectsForUser({#required List<String> shares}) {
var ref = _firestore.collection('projects');
return ref
.where(shares, arrayContains: ref.id)
.snapshots()
.map((QuerySnapshot snapshot) => snapshot.docs.map((DocumentSnapshot doc) => doc.data()).toList());
}
I also tried this:
Stream<List<Map<String, dynamic>>> getListOfProjectsForUser({#required List<String> shares}) {
var ref = _firestore.collection('projects');
return ref
.where(shares, arrayContains: FieldPath.documentId)
.snapshots()
.map((QuerySnapshot snapshot) => snapshot.docs.map((DocumentSnapshot doc) => doc.data()).toList());
}
Is what I'm trying to do even possible? I've been messing with this for two days and my head's exploding. Any help would be greatly appreciated. Thanks in advance.
You'll need two operations.
Read the document for the user, to determine the list of project IDs.
Perform a in query for the project documents matching those IDs. The in operator accepts up to 10 IDs, so if you have more than 10 projects you'll need multiple queries and merge the results in your application code.
var citiesRef = db.collection("projects");
citiesRef.where(FieldPath.documentId, arrayContains: ['project1id', 'project2id']);
Also see:
The FlutterFire documentation for the where(field, whereIn:) operation
The FlutterFire documentation for the FieldPath.documentId field
First off, how can I get each document in the share list's ID?
For this, you're required to actually query the entire collection. You can iterate the results to collect the IDs of each document. There is no easy way to just get a list of IDs directly from web and mobile client code. See: How to get a list of document IDs in a collection Cloud Firestore?
And secondly, is it possible to compare that ID to the contents of a List using a .where() clause?
If you have a list of document ID strings in memory that could be any length, you will need to perform a query filtering projects for "projOwner" for each individual ID. There are no SQL-like joins in Firestore, so you can't simply join the two collections together with a single query.
Here's how you do a single one - you have to call out the name of the field to filter on:
firestore
.collection("projects")
.where("projOwner", isEqualTo: id)
If you have 10 or less share IDs in the list, you can use an "in" query to find matches from projects, and it will not work with any more.
firestore
.collection("projects")
.where("projOwner", whereIn: listOfIds)
So, if you think the list could ever be larger than 10, you should just start by performing individual queries for each share ID.
if 'arrayContains' is not working try 'whereIn'.
var citiesRef = db.collection("projects");
citiesRef.where(FieldPath.documentId, whereIn: ['project1id',
'project2id']);

arrayContains in subCollection

Cant seem to understand if arrayContains works on subCollections in Firestore.
This code does not return any data
Firestore.firestore()
.collection("all_chatrooms")
.whereField("postmoderators", arrayContains: userId)
However specifying the targeted collection path does...
Firestore.firestore()
.collection("all_chatrooms")
.document("randomId")
.collection("chatroom")
.whereField("postmoderators", arrayContains: userId)
is there a way to search for an array within subCollections without specifying a documentId?
Do you maybe have to store userIds within a map to be able to search within subColletions?
Firestore queries are shallow, meaning that when you query a specific collection "C1", only the documents from this collection are returned, and not the documents in the subcollections of the documents in "C1".
However, in your case, Collection Group queries may "come to the rescue". As indicated in the doc:
A collection group consists of all collections with the same ID. For
example, if each document in your cities collection has a
subcollection called landmarks, all of the landmarks subcollections
belong to the same collection group.
So if all the docs in the all_chatrooms collection have a subcollection named chatroom you can use a Collection Group query as follows:
Firestore.firestore().collectionGroup("chatroom").whereField("postmoderators", arrayContains: userId)
Of course, by doing so you will get ALL the docs (with userId in postmoderators) in ALL the chatroom subcollections of ALL the docs in the all_chatrooms collection.

Query Firebase Firestore Subcollection in Flutter

I am querying my Firestore database as follows:
final Query roasters = Firestore.instance
.collection('retailers')
.where('retail_category', isEqualTo: 'Coffee Roasters');
I am receiving the result back of all documents in the retailers collection which have 'retail_category' set as 'Coffee Roasters'.
The Problem
I instead want to turn retail_category into a separate collection and instead reference it in the retailer field (which would negate the following reference):
"retail_categories/hEN5fzNl2hEc2tEs05Wi"
I have tried the following:
final Query roasters = Firestore.instance
.collection('retailers')
.where('retail_categories', isEqualTo: ' qretail_categories/hEN5fzNl2hEc2tEs05Wi');
Here is my Firestore configuration:
Retailers
Retail Categories
It's not possible to reference data in documents outside of the collection being used for the query. For this reason, it's very common to duplicate data between documents that need to be used in queries for each collection. If you don't want to do that, you will have to make separate queries for each referenced document.

Flutter Firestore Query Nested Subcollections

I am trying to query subcollection in Firebase, but I always get an empty list...
This is my query:
Firestore.instance.collection('messages').where('idFrom', isEqualTo: userID).snapshots();
I know that I have subcollection with another subcollection here..
/messages/RWzG98s92mVTZniofez6YoYsNhA3-tT2Q16n1FMZoTNZQOejtWuJdCmD2/RWzG98s92mVTZniofez6YoYsNhA3-tT2Q16n1FMZoTNZQOejtWuJdCmD2/1579394957103
And my question is how to query these types of models?
Since Firstore queries are always shallow, you have to build the path to the subcollection to query.
Firestore.instance
.collection('messages')
.document(...) // ID of the nested document
.collection(...). // ID of the nested subcollection
.where('idFrom', isEqualTo: userID);
There is no way to avoid giving those nested IDs. If you can't identify the full path of the subcollection to query, you won't be able to access its documents.

Resources