DocumentID search in Firestore with a List - flutter

Can i search a Firestore DocumentID with a List<String>?
I am trying to search through my collection with some selection of documentID in a List. The List will consist of few String. Can I search through the Firestore collection using this?
This is the List:
List<String> _selectedBusStop = List<String>();
This is the code I used in finding the DocumentID based on the list that is in here.
Future <void> saveRoute(_selectedBusStop) async{
Firestore.instance.collection('markers').where('BusstopName', isEqualTo: _selectedBusStop)
.snapshots().listen((location) {
if(location.documents.isNotEmpty){
for (int i = 0; i < location.documents.length; i++){
initRoute(location.documents[i].data, location.documents[i]);
}
}
});
setState(() {
});
}
I am using where and isEqualTo or is this approach wrong? Any idea how to make it work for this part? Thank you in advance for your help.
Update:
This is how my Firestore looks like:
The List have some of the BusstopName but not all of it. I do not want to retrieve all the data from the Firestore just the one that is in the List. Sorry for causing so many misunderstanding.

Use the whereIn operator, like this:
Future <void> saveRoute(_selectedBusStop) async{
Firestore.instance.collection('markers').where('BusstopName', whereIn: _selectedBusStop)
.snapshots().listen((location) {
if(location.documents.isNotEmpty){
for (int i = 0; i < location.documents.length; i++){
initRoute(location.documents[i].data, location.documents[i]);
}
}
});
setState(() {
});
}

Assuming your documents have a unique id stored in the field BusstopName and also the documents actual id matches the content of this field, you have 2 possibilities.
(1) .where query
query data with collection("markers").where("BusstopName", "=", "yourBuststopId").
this returns a querySnapshot Object, on which you can call .size to check if there were any documents with that Id found (could be more than 1 if you have an inconsistent database).
(2) .doc query
query data with collection("markers").doc("yourBuststopId")
this returns a documentSnapshot Object, on which you can call .exist to check if the document actually exsists.
In both cases you need to do 1 query per Id, because Firestore queries only support equality and range operations. See this similar SO question. I would suggest to do the queries asynchronously, otherwise the time to execute will increase with the size of the array.
If you are concerned about costs, you only get billed for the results that actually return documents that exist.

you might also try this:
FirebaseFirestore.instance
.collection('markers')
.where('BusstopName', arrayContainsAny: ['Utar Bus Stop', 'Garden Bus Stop'])
.get()
.then(...);
Taken from the examples documentation

Related

flutter/firebase/dart: get data from firestore

How to get docs id from some matching condition?
I was able to get this to work:
Future getChat({required String userIdsArr}) async {
var docId = '';
await chat.where('User ids', isEqualTo: userIdsArr).get().then((value) {
value.docs.forEach((element) {
docId = element.id;
});
});
//print(docId);
return docId
}
this returns the correct record, however, I think this is a terrible way of quering the database because I have to fetch all the records everytime.
Is there a way to write this so that I get the doc Id of the matching condition?
Unfortunately, there is not a better way to accomplish this. When you use the where clause though, it won't fetch everything like you suspect, only records that contain the value you are querying for. I don't believe it's as expensive of a call as you might think.

Iterate through all documents and sum a field - Firebase

I have iterated through all documents of specific collection and made the sum of specific property/field to get the total amount, I able to did it but the problem is that this method is not effective in terms of performance and cost performance because firebase charges according to the usage (read/write document)
So what could be the better approach to do it?
here is my code
basically there is an sub collection called 'userEntries' and it has lots of document and each document has a field called 'amount'
double totalAmount = 0;
void getTotalAmount() async {
QuerySnapshot customerEntries = await FirebaseFirestore.instance.collection('entries').doc(widget.firebaseUser!.uid).collection('userEntries').where('customerId', isEqualTo: widget.customerMap['customerId']).get();
double total = 0;
for (var element in customerEntries.docs) {
total += element['amount'];
}
setState(() {
totalAmount = total;
});
}
What I can think of is maintain a separate sub collection where I would write/update totalAmount field whenever a user would make a new entry, is it right way to do it?
What I can think of is maintain a separate sub collection where I
would write/update totalAmount field whenever a user would make a new
entry, is it right way to do it?
Yes, this is the right way to do that. There is a specific page in the Firestore documentation which explains how to do that with several documents in order to solve the maximum limit of one write to a document per second.
The code examples in this page do not show the Dart version but it is easy to implement it based on the JS example.

How can I get a collection inside a QuerySnapshot

On the explore page, I get() the entire users collection to create a user list and search results. Inside each of those user documents is a collection posts that I also need to get to create a GridView of each post. I want to reuse that users collection QuerySnapshot instead of fetching each posts collection again to save money. Is this possible?
Here is my current function:
void fetchUsers() async {
final userRef = FirebaseFirestore.instance.collection('users');
final QuerySnapshot result = await userRef.get();
final docs = result.docs.asMap();
docs.forEach((index, value) {
final profile =
ProfileObject.fromJson(value.data() as Map<String, dynamic>);
usersList.add(UserSearchResult(profile, value.id));
/// Below is the code for getting the posts, not working, need ideas
final QuerySnapshot postsResult = value.get('posts');
final posts = postsResult.docs.asMap();
posts.forEach((index, value) {
final post = Post.fromJson(value.data() as Map<String, dynamic>);
postsList.add(post);
});
});
print(usersList);
print(postsList);
}
Here is the structure of my Firestore:
users
uid (doc)
posts (collection)
info (fields)
uid (doc)
posts (collection)
info (fields)
It is not possible to call a collection to get all sub-collections. You should restructure your database to include sub-collection data in document itself. You can use a map or list for that. But remember, calling everything in one go may end up in slow performance and you might end up losing your customers. So the best way is to include the info in every posts' documents. That way, you won't loss your money and user won't feel lag in performance.
It is not possible. You fetch a document, then fetch the (sub)collection under it.
Subcollection data are not included in the initial document snapshots because Firestore queries are shallow. There shouldn't be any cost savings that you can do there?
See the similar Q&A:
Firestore: Get subcollection of document found with where

Using fields in a document for another query

I have 2 collections, one called Timeline and one called Posts. The first one is very simple, having 2 fields: 'PostId' and 'OwnerId', while the second one is a little bit more complex but it is not important for the purpose of my question.
Using 'OwnerId' and 'PostId' I can get a specified post in the collection Posts.
What I want to do is getting all the docs in timeline of a specified user, for each doc use it to get the post infos in Posts collection, and order the posts in descending timestamp, but I can't find a smart and effective way to do so.
To get all the docs of a specified user in Timeline I write:
QuerySnapshot snapshot = await timelineRef
.doc(currentUserID)
.collection('timelinePosts')
.get();
And to get a specified post from Posts collection I write:
QuerySnapshot snapshot = await postsRef
.doc(ownerId)
.collection('userPosts')
.doc(postId)
.get();
How can I mix these two to get the result I want? Thank you
There is no concept of a server-side join in Firestore, nor is there a way to filter the documents returned based on information in documents in another collection. All Firestore queries can do is evaluate the literal data in the candidate documents (through an index) and filter based on that.
So you will either have to duplicate the data to filter on in each userPosts document, or perform a so-called client-side join - with the latter being the most reasonable option for this use-case as far as I can see.
You'll end up with individual get() calls for the documents, or a bunch in in queries on the FieldPath.documentId() you get from timelinePosts, and then merge the results in your application code.
At the moment I found a solution that is not very elegant but at least is working:
QuerySnapshot snapshot = await timelineRef
.doc(widget.currentUser.userID)
.collection('timelinePosts')
.orderBy('timestamp', descending: true)
.get();
List<TimelineItem> timelineItems =
snapshot.docs.map((doc) => TimelineItem.fromDocument(doc)).toList();
List<PostWidget> postsTemp = [];
for (var element in timelineItems) {
DocumentSnapshot documentSnapshot = await postsRef
.doc(element.ownerId)
.collection('userPosts')
.doc(element.postId)
.get();
postsTemp.add(PostWidget(Post.fromDocument(documentSnapshot)));
}
I added timestamp field to my timelinePosts, created a class to contain the data from the first query, and then I did a second query based on the parameters I got on the first one for each doc.
Hopefully I'll find a more efficient solution but at the moment I use this

I am trying to use a field from the collection 'profile' say 'username' to filter the records from the main collection 'orders'

Is there a way to achieve this?
i have tried to assign the entry to a local variable but it doesn't work with crudmethods.
getData() async {
String userId = 'userId';
Firestore.instance.collection('user').document(userId).snapshots();
var snapshot;
var userDocument = snapshot.data;
String _myAddress = userDocument["address"];
return Firestore.instance
.collection('letters')
.where("source Box", isEqualTo: _myAddress)
.snapshots();
}
Yes, you should be able to use a document in the query of another document.
For this, you need to create a reference for one collection and use it in another one.
The below code is an example that you can give it a try adapting further for your case, but that I believe should help you.
// Create references to the profile and orders collections
var profilesRef = db.collection("profile");
var ordersRef = db.collection("orders");
// Create a query against the collection.
var query = ordersRef.where("username", "==", ).doc("username").get();
In the documentation Perform simple and compound queries in Cloud Firestore, there is more information and example of queries that should help you.
In addition to that, this below post from the Community can provide you some insights on how to achieve this type of query as well.
How can I get specific document data from firestore querysnapshot?
Let me know if the information helped you!