Get detail information from master-detail collection in firestore - firebase

I have created a simple app using flutter and firebase firestore database. There are 'users' collections and each user has 'posts' collections. Each post may have one or more posts added by different users.
I am trying to get all the posts regardless of users. However, my current function was written for reading records only shows the posts relevant for login user, not all the posts.
Stream<QuerySnapshot> readItems({required String collectionName}) {
CollectionReference detailCollection = _firestore
.collection(mainCollectionName!)
.doc(userUid)
.collection(collectionName);
return detailCollection.snapshots();
}
Here, I pass 'users','login user's uid' and 'posts' as mainCollectionName, userUid and collectionName respectively. Can anybody guide me how do I get all the posts regardless of users?

After searching I found a solution here. The following method gives the desired output.
Stream<QuerySnapshot> readItems({required String collectionName}) {
Query<Map<String, dynamic>> detailCollection = _firestore.collectionGroup(collectionName);
return detailCollection.snapshots();
}

It is possible to get all sub collections data from all the documents in a collection. Try this way
_firestore
.collection(`${mainCollectionName}/*/${collectionName}`)
.get()
Refer to this page for more details about querying collections and sub collections - https://firebase.googleblog.com/2019/06/understanding-collection-group-queries.html

Related

How to get data from firebase sub collection?

Im trying to get data from firebase but im a bit struggling . I have this videos collection where I saving video ids and thenevery video has documetnfield and also a sub collection called user votes . In side that im saving the user votes from the ratingbarindicator
this is how to collection looks
So what I want is every document of the user votes sub colletion and then the each rating field .
but how can I do that ?What I want is calculating that together Hope anyone can help
To read the data from all (sub)collections with a given name, you can use a collection group query.
FirebaseFirestore.instance
.collectionGroup('uservotes')
.get()
...
Also see:
Is wildcard possible in Flutter Firestore query?
Fetch all the posts of all the users from Cloud Firestore
you can go through collection and document like this with firebase:
final querySnapshot = await FirebaseFiresotre.instance.collection('videos').doc([theVideoDocumentID])
.collection('uservotes').get();
final docs = querySnapshot.docs;
for(final doc in docs) {
final data = doc.data();
//handle each document here
}

Flutter Firebase Cloud Firestore How to filter a stream with where() query using a subcollection

So i have in my Cloud Firestore I have a collection of recipes that contains documents(with casual ids) with different recipes. Every document has a 2 fields with the recipe name and the recipe duration.
Every document has also a collection named likedBy where there is documents that have as ids user ids and have a single field with the date of the like.
Now i want to return all recipes that have in their likedBy subCollection the userId.
i' ll write what i' ve tried with only essential code.
String userId= 'uiuu4fn3fff4fu';
Scaffold(
body:StreamBuilder(
stream: THE STREAM THAT I NEED,
builder:(context,snapshot){
return ListView.builder(
itemCount: snapshot.data.documents.length
itemBuilder:(context,index){
return Column(children:[
Text(snapshot.data.documents[index]['recipeName']),
Text(snapshot.data.documents[index][recipeDuration]),]) } ) } ) )
What i want is to return only documents that have in their likedBy subCollection a specific user uid.
I' ve tried with this stream
Firestore.instance.collection('recipes').parent().collection('likedBy').where(FieldPath.documentId,
isEqualTo,userId).snapshots()
But it doesn' t work and i have no idea what else i can try.
Any help is highly apprecieted.
Items should not be added by the users but by admins, that means that there will be a list of items added by admins and a list of users that can add them in favorites and what i want to achieve is that users can see all their favorites in the order in which they saved them. To be clear i want something like Instagram functionality to save posts.
So you want a way to query subcollection. To do that simply use collectionGroup method:
db.collectionGroup('likedBy').where('userId', '==', '1');
To order by a value use timestamp:
// add to your document
db.collection("items")
.add({...item, created: firebase.firestore.Timestamp.fromDate(new Date()) })
and to orderby this value use orderby:
db.collection("items")
.orderBy("created", "asc")
What you might want to do instead is have a 'likedBy' property on the recipe document instead of its own sub-collection. If it is just a list of userids that should be no problem. Then you can just say recipeCollection.where(likedBy, array contains: userId)

Firebase Firstore subcollection

please how can I get all the value of my IndividualTaxData subcollection in Flutter.
First, you must get the reference to the parent document:
DocumentReference parentRef = Firestore.intances.collection('TaxData').document(taxDataId);
You can do the previous part with a direct reference to the document (like the code above) or with a query. Later, you must get the reference of the subcollection and the document that you get the information:
DocumentReference subRef = parentRef.collection('IndividualTaxData').document(individualTaxId);
And finally, get the data:
DocumentSnapshot docSnap = await subRef.get();
For you to return a simple document, you can use the following code for it.
var document = await Firestore.instance.collection('IndividualTaxData').document('<document_name>');
document.get() => then(function(document) {
print(document('character'));
// you can print other fields from your document
}
With the above code, you will reference your collection IndividualTaxData and then load it's data to a variable that you can print the values.
In case you want to retrieve all the documents from your collection, you can start using the below code.
final QuerySnapshot result = await Firestore.instance.collection('IndividualTaxData').getDocuments();
final List<DocumentSnapshot> documents = result.documents;
documents.forEach((data) => print(data));
// This print is just an example of it.
With this, you will load all your documents into a list that you iterate and print after - or that you can use with another method.
In addition to that, as future references, I would recommend you to check the following links as well.
Query a single document from Firestore in Flutter (cloud_firestore Plugin)
How to use Cloud Firestore with Flutter
Le me know if the information helped you!

Fetch all the posts of all the users from Cloud Firestore

I am building a Flutter app. Cloud firestore database structure is given in the picture. I want to get all the posts of all the users using a StreamBuilder. How can I do that? So far I have tried this :
Stream<List<PostModel>> jobs() {
return usersCollection.snapshots().map((snapshot) {
return snapshot.documents.map((doc) {
doc['posts'].map((docu) {
return PostModel.fromSnapshot(docu);
});
}).toList();
});
}
If you want all the document in all of the subcollections called "posts" (for all users), then you probably want a collection group query using collectionGroup():
db.collectionGroup("posts").snapshots()...
This will give you all documents in any collection or subcollection called "posts", no matter where it's nested.

how to delete one to many associations in flutter firebase

I am developing a flutter application and I am using firebase database as a database service.
Now my since my app is a task management app my database have three main collections:
+roles
+tasks
+users
every role is a document with a unique id and name
every task is a document with a unique id a name and a role id
now in the app the user is able to add roles in the database I just add a new role document to the roles collection
but I am stuck when it comes to deleting a role.
Obviously roles and tasks are a one-to-many association since one role can be associated with none or more than one task but one task can at most have only one role.
So when I want to delete a role I have to delete the associated tasks with it as well and only deleting the role will then generate a null error in the task since it doesn't find the specified role in the database anymore.
Now I really don't find any hint in the flutter firebase documentation on how to delete more than one document based on a selected criteria.
for example deleting one document based on its document id is straightforward
Future<void> deleteRole(Role role) {
final reference = databaseInstance.document('/roles/${role.id}');
return reference.delete();
}
if i want to read a task based on certain criteria like someId i will just write something like this
Stream<List<Task>> readTasksStream({#required String someId}) {
Stream<QuerySnapshot> snapshots = databaseInstance
.collection('tasks')
.where('someId', isEqualTo: someId)
.snapshots();
//now deserialize the data to objects and return it
return snapshots.map((snapshot) => snapshot.documents
.map((snapshot) => Task.fromMap(snapshot.data))
.toList());
}
but how can i actually do the same for deleting a task based on someId in this case the roleId.
Something like this:
deleteTasksAssociatedWithARole({#required String roleId}) {
Stream<QuerySnapshot> snapshots = databaseInstance
.collection('tasks')
.where('someId', isEqualTo: someId)
.snapshots();
//now I want to delete the selected document from the querysnapshot
// but how ????????
}
I hope you get what I want to do here.
Any suggestion or help is very welcomed.
Thank you so much
To delete all documents matches by the query, you loop over the stream for forEach and then delete them each in turn.
Something like:
snapshots.forEach((snapshot) => snapshot.documents
.forEach((snapshot) => Task.fromMap(snapshot.data))
.toList());
}
snapshots.forEach((document) => document.reference.delete());
I find it easiest to figure out how to do this by following the types in the reference documentation, in this case from the snapshots property.
Frank van Puffelen
thank you so much it worked now.
so the final code is like this:
Future<void> deleteTasksAssociatedWithARole({#required Role role}) {
Stream<QuerySnapshot> snapshots = databaseInstance
.collection('tasks')
.where('roleId', isEqualTo: role.id)
.snapshots();
return snapshots.forEach((snapshot) =>
snapshot.documents.forEach((document) => document.reference.delete()));
}
so instead of deserializing the document snapshots to objects you loop through them with a forEach loop extract its reference to delete the document.

Resources