how to where query a collectionGroup in firestore flutter? - firebase

I need to query a collectionGroup with where clause and While doing it I stumbled on to a thing.
var payData = FirebaseFirestore.instance.collectionGroup("payment").where("balance", isNotEqualTo: 0);
While executing the above code when I tried to print payData it prints Instance of _JsonQuery. How to access the data inside that variable and what's its structure.
I think the above code is incorrect.
var payData = FirebaseFirestore.instance.collectionGroup("payment").where("balance", isNotEqualTo: 0).getDocuments();
After surfing I got through the above code but VSCode says it's an error in getDocuments()
So, What I need is to print the data that is in the variable for the query I used above.

getDocuments() was deprecated in favor of get() in version 0.14.0 of the cloud_firestore package (Release notes). You need to call this method on your Query, i.e. payData.
The get() method returns a Future, so you can use then() as follows:
FirebaseFirestore.instance
.collectionGroup("payment")
.where("balance", isNotEqualTo: 0)
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
print(doc["<name_of_a_field_in_the_doc>"]);
});
});
However, most of the times you will use one of the approaches shown in the FluterFire doc: depending on whether you want to read the data once or listening to changes in realtime you will use a FutureBuilder or a StreamBuilder.

Related

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

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.

firebase index query implementation

Added a query mentioned below and also created the index in firebase but I don't know what happened since yesterday it is not showing data as per this query and if I remove this:- .where('age', isLessThanOrEqualTo:currentUser.ageRange['max']) from the below query then it shows the data other wise no data. Earlier this was working fine with no problem.
I have tried flutter clean but still no success, pls help me out as I want to implement this in project.
query() {
if (currentUser.showGender == 'everyone') {
return docRef
.where('age', isGreaterThanOrEqualTo: currentUser.ageRange['min'])
.where('age', isLessThanOrEqualTo:currentUser.ageRange['max'])
.orderBy('age', descending: false).limit(docLimit);
} else {
return docRef
.where('editInfo.userGender', isEqualTo: currentUser.showGender)
.where('age', isGreaterThanOrEqualTo:currentUser.ageRange['min'])
.where('age', isLessThanOrEqualTo: currentUser.ageRange['max'])
.orderBy('age', descending: false).limit(docLimit);
}
}
I believe the issue might be because of you're trying to run two range queries separately.
You may won't be able to do that as it's one of the limitation of querying.
You can try including both the comparisons in the single query like
.where("age",isGreater... : x, isLess..: y)
You can read about how querying works in firebase here:
https://firebase.google.com/docs/firestore/query-data/queries

Firebase DocumentReference.update is deleting the document

I have flutter code that I have been using for a while that I use to perform crud operations on my firestore documents. I have one situation where an update appears to be deleting a document. I have put a breakpoint in my code just before the update and hold a reference to the document in the firestore console. As soon as the update runs, the document is removed from firestore. Does this make sense? Is there any condition that would cause a document to be deleted when invoking a DocumentReference.update? Here is a snippet of my code showing the update I am trying to perform:
Future<void> updateInMyCartIndicator(
ShoppingListItem shoppingListItem) async {
logger.d("FSShoppingListItemHelper:updateInMyCartIndicator - ENTRY");
try {
CollectionReference shoppingListItemCollection =
FirebaseFirestore.instance.collection('shopping_list_items');
QuerySnapshot shoppingListQuery = await shoppingListItemCollection
.where("id", isEqualTo: shoppingListItem.id)
.get();
final DocumentReference docRefShoppingListItem =
shoppingListItemCollection.doc(shoppingListQuery.docs[0].id);
await docRefShoppingListItem
.update({'in_my_cart': shoppingListItem.inMyCart});
logger.d(
"FSShoppingListItemHelper:updateInMyCartIndicator - Update complete");
} catch (e) {
logger.d("FSShoppingListItemHelper:updateInMyCartIndicator - Exception");
print(e.toString());
}
}
I have tried to reproduce this behavior and no matter how did I update a document (empty HashMap as argument, null fields, etc..) it was not getting deleted. As such the most likely scenario is that the document gets deleted somewhere else in your code, probably as an unintended side effect.
Thanks for the response. I was able to get past this. Honestly, all I did was kill the simulator and my ide and the deleting stopped. I can’t explain why it was happening, but it has gone away.

Update Firebase Array using.where(). But, getting error ".update isn't a function

So, I am trying to update a document in my firebase that has an array.
Currently, a users document may look like this.
username : John
postedProjects : ['project-one','project-two']
However, as John submits "project-three" to another collection, I want to grab johns document, and add "project-three" into his array.
Here is my code currently (Please note, I am not using the document
UID as I have set UID as name, but the user may change their username
down the line, but their UID remains the same)
var newProject = db.collection('users').where('user_id', '==', this.userInfo.user_id);
newProject.update({
postedProjects: firebase.firestore.FieldValue.arrayUnion("test")
})
This is the code I have followed from the Firebase doc, with the slight adjustment of changing .doc(uid) to .where, to instead match the existing user to the one on the collection.
However, I get an error stating "newProject.update is not a function".
-- Added .where but still getting error as i am not sure where to put the "update()"
db.collection('users').where('user_id', '==', this.userInfo.user_id)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
doc.data().update({
postedProjects: firebase.firestore.FieldValue.arrayUnion("new project")
})
})
})}}
where() returns a Query object, which doesn't have an update() method, as you can see from the linked API documentation. Since there is no guarantee how many documents could result from executing a query, you will have to get() the query, then iterate the results to find a DocumentSnapshot that matches document, use its ref property to get a DocumentReference for it, and finally update() the document using that DocumentReference.

Resources