how can i get firestore collection and subcollection in flutter - firebase

Thank you for reading my question.
My English may not be good enough before I ask you a question.
this my firestore structure
I'm using a flutter and I have to bring the product collection and subcollection image together from the FireStore.
I succeeded get data, but I don't know how to use it as a streambuilder.
FirebaseFirestore.instance
.collection("products")
.get()
.then((value) async => {
for (DocumentSnapshot document in value.docs)
{
log(document.data().toString()),
await document.reference
.collection("images")
.get()
.then((value) => {
for (DocumentSnapshot document
in value.docs)
{
log(document.data().toString()),
}
}),
}
});
code run log result
I looked for it for three days, but I couldn't find the answer.
Please reply.
Have a nice day. Thank you.

The only way I have found to do this is to use 2 different streambuilders, naming each snapshot differently. Use one for the products collection, then images for the other. What I would recommend is to add a field of 'images' in your product document and make it an array of string types. This will allow you to reference the images straight from each product document

Related

Get detail information from master-detail collection in firestore

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

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."

Flutter Firebase How to get random document

I am trying to get some random posts from Firebase. But i am unable to get random document id.
Is there any way to retrieve data from Firebase like this :-
getRandomData() async {
QuerySnapshot snapshot = await posts
.document(random.id)
.collection('userPosts')
.getDocuments();}
i am trying to say that. Now i am able to get documentID normally not in italics.so now how can i get random documentID from Firebase.
List documentIds in a list first.
var list = ['documentId1','documentId2','documentId3'];
var element = getRandomElement(list);
Then query the documentSnapshot
You can first get all documents in you collection.
Try this code:
async getMarker() {
const snapshot = await firebase.firestore().collection('userPosts').get();
const documents = [];
snapshot.forEach(doc => {
documents[doc.id] = doc.data();
});
return documents;
}
Next, from return documents you can create a list of documents id and get random numbers (document id) from this list.
The main problem here that's going to prevent you from moving forward is the fact that you don't actually have any documents nested immediately under "posts". Notice that the names of the documents are in italics. That means there isn't actually a document here at all. The reason why they are show, however, is because you have a subcollection "userPosts" nested under the path where that document ID exists.
Since you don't have any documents at all under "posts", the usual strategies to find a random document won't work at all. You're going to have to actually populate some data there to select from, or find another way to select from the data in the subcollections.
firestore()
.collection('SOURCE')
.doc(props?.route?.params?.data?.id)
.collection('userPosts')
.get()
.then(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
console.log('User ID: ', documentSnapshot.id, documentSnapshot.data());
})
})

how do I check collection exists or not in firestore on flutter?

I get some data from firestore. Sometimes when I called to get data, the collection is not created yet.
before calling get request, how do I check collection is exists or not?
Stream<List<ChatModel>> getChat(ChatFieldModel model) {
var ref = _db.collection('chats');
return ref
.document(model.docId)
.collection('messages')
.orderBy('timestamp', descending: true)
.snapshots()
.map((list) =>
list.documents.map((doc)=>ChatModel.fromForestore(doc)).toList());
}
I posted this before
final snapshot = await firestore.collection(roomName).getDocuments();
if (snapshot.documents.length == 0) {
//doesnt exist
}
Hope this helps
Collections are not created or deleted independently of documents. When you create a document and specify it as being part of a certain collection, that collection is created automatically if it does not already exist. Similarly, when you remove the last document in a collection, that collection will automatically be deleted. So there is really no circumstance where you need to worry about whether a collection has been created or not, and you have no explicit control over creating or deleting collections.
Usually a collection in Firestore gets deleted if no Documents exist in it.
However, there might be cases where you want to keep a history of the collection modification events, or let's say for some reason prevent Collections from being deleted.
Or for example, you want to know when a collection was created in the first place. Normally, if the Documents are deleted, and then the Collection gets created again, you will not know the initial creation date.
A workaround I can think of is the following:
Initialize each collection you want with a Document that will be specifically for keeping generic info about that collection.
For example:
This way, even if all other Documents in the Collection are deleted, you'll still keep the Collection in addition to some info that might be handy if In the future you need to get some history info about the Collection.
So to know if a Collection exists of no, you can run a query that checks for a field in Info Documents (eg CollectionInfo.exists) to know which Collections have been already created.
This is for the most recent update
final snapshot = await FirebaseFirestore.instance
.collection('collection name').get();
if ( snapshot.size == 0 ) {
print('it does not exist');
}
Feb 2022
Get QuerySnapshot and return querySnapshot.docs.isNotEmpty or isEmpty
Future<bool> isItems() async {
CollectionReference collectionReference =
_firestore.collection("users").doc(_user!.uid).collection("cart");
QuerySnapshot querySnapshot = await collectionReference.get();
return querySnapshot.docs.isNotEmpty;
}
await FirebaseFirestore.instance
.collection('collectionName')
.limit(1)
.get()
.then((snapshot) {
if (snapshot.size == 0) {
print("No collection");
}
});

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