Flutter Firestore - How to get data from a Document Reference in a Document Field? - firebase

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

Related

Firebase Firestore Getting documents again on query stream

FirebaseFirestore.instance
.collection(
'chats/${site}/conversations/${room.id}/messages')
.orderBy('createdAt', descending: true)
.where("createdAt", isGreaterThan: dateTime )
.snapshots()
.map(
(snapshot) {
So, On the first document that inserted to the firestore, the I get i a snapshot. On the second, the stream return the first and the second,
So the i get -
(Doc A)
(Doc A,Doc B)
(Doc A, Doc B, Doc C)
And so on. Is there a way to get:
(Doc A)
(Doc B)
(Doc C)
?
I reviewed your snippet and it appears you are using a Stream from the snapshot() method of a CollectionReference type. According to the documentation, this will stream events as they happen in Firestore. You mentioned that with each document inserted in Firestore, you also started getting the previous documents that were inserted before, instead of getting only the one which was just inserted (the latest). This might be related to the dateTime variable you are using to filter documents. Since you are using a greater than comparison, any documents created after the time set in the dateTime will be returned from the query. This could explain why your query returns additional documents each time a new one is added with a timestamp after the dateTime variable.
If you would like to get only the latest document added to the database each time, you can make use of a query limiter. I tested the limitToLast method to get only the latest document added and it appears to work in my testing. This method returns the very last document in a query, and in order for this to be the newest you would have to invert the process to order by ascending (oldest first) so that the newest document is at the bottom:
FirebaseFirestore firebase = FirebaseFirestore.instance;
firebase
.collection('users')
.orderBy('createdAt', descending: false) // orders by ascending order, latest document is the last
.limitToLast(1) // gets the last document, you can set how many docs to get
.get()
.then((QuerySnapshot snapshot) {
if (snapshot != null) {
// Data is available
snapshot.docs.forEach((doc) {
print(doc['firstName']);
});
} else {
print("No data found");
}
}
for everyone who reach this issue on 2022, the solution is rather simple.
You can stay with the same query but check the doc changes:
snapshot.docChanges.forEach((docChange) {
final data = docChange.doc.data() as Map;
LimitToLast won't solve your problem if the internet connection was down for a few moments and multiple updates arrived, but docChanges is all the changes since the last snapshot.
Note: You need to ignore the first time because it will return all the docs on the collection at the first time.

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 to retrieve unknown sub collection from document in flutter

I have the following code with the objective of retring all the documents like this: Collection('A').document(currentUser), this should give me the document YRZ1**** as you may see in the first image. Now what I want to do is get all the documents in the t22o9*** subcollection, as showned on the second image, how can I do that?
var docPath=Firestore.instance.document('Messages/$currentUser');
docPath.snapshots().listen((event) {
print('Hello 12 ${event.data}');
});
In order to get data from subcollection you can do the following:
var db = Firestore.instance;
//This is a reference to the YRZ1**** doc
var messagesDoc = db.collection('Messages').document('Messages/$currentUser');
//collectionId is the t22o9*** id, you need to have this set previosly in your code
var docList = [];
messagesDoc.collection(collectionId)
.getDocuments()
.then((QuerySnapshot snapshot) {
snapshot.documents.forEach((doc) => docList.add(doc)'));
});
With this code, docList will be a list of the documents located at your subcollection t22o9*** of the YRZ1*** document.
Also you can check this link with some examples on how to get data from firestore using flutter.
EDIT:
As per what you have clarified on the comments, getting the subcollection data is a bit more complicated with subcollections that were created dynamically, as you can see on this link, which I assume is the case you have. The most feasible solution in your case would be to create a list of ids of subcollections in your parent document, so for example your YRZ1*** document would have this structure
document
id: YRZ1***
subCollectionIds : [subCollectionId1, subCollectionId2,...]
subCollection1
subCollection2
...
subCollectionN
Having this structure you could use this code to retrieve the list of subcollections and the first document of each subcollection, ordered by whatever field you'd like:
var db = Firestore.instance;
var listFirstDocSub = []
//This is a reference to the YRZ1**** doc
db.collection('Messages')
.document('Messages/$currentUser')
.getDocument()
.then((DocumentSnapshot doc) {
var listSubCollections = doc["subCollectionIds"];
listSubCollections.forEach((id) {
db.collection('Messages')
.document('Messages/$currentUser')
.collection(id)
.orderBy("WHATEVER_FIELD_YOU_DECIDE")
.limit(1)
.getDocuments()
.then((DocumentSnapshot snapshot) {
listFirstDocSub.add(snapshot);
})
});
});
NOTE: With this approach, everytime you add a new subcollection, you will also need to add it's id to the subCollectionIds list.
Hope This helps.

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!

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");
}
});

Resources