0

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: Firestore

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.

  • 1
    does this code work or not? If not, what is the error message you are getting? Also to clarify, is `_selectedBusStop` a documentId or the content of the field `BusstopName` in the document? – dcts Aug 18 '21 at 10:40
  • 1
    Do you need documents where `BusstopName` (array field) is exactly equal to `_selectedBusStop` List or that array contains any value from `_selectedBusStop` ? – Dharmaraj Aug 18 '21 at 10:40
  • 1
    if its a documentId you can asynchronously make requests to `collection("markers").doc("yourDocumentId")` and then filter out only the documentSnacpshots that actually exist. (you can call DocumentSnapshot.exists). You would need to check the flutter firestore sdk documentation to get the correct syntax. – dcts Aug 18 '21 at 10:44
  • `_selectedBusStop` is the DocumentID and as well as one of the Data inside the document. Sorry for not making it clear. @thomas – randomstudent Aug 18 '21 at 10:46
  • actually the `BusstopName` is not an array field it is only a `String`. The name of the DocumentID is actually the same as the `BusstopName` in the document. I will update my question. Sorry for causing so many misunderstanding. – randomstudent Aug 18 '21 at 10:53

3 Answers3

1

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(() {
    });
  }
Huthaifa Muayyad
  • 11,321
  • 3
  • 17
  • 49
  • I get a message saying that the `DocumentSnapshot` is not a subtype of type `String`. And also can you explain more like what does `whereIn` does? Thank you so much. – randomstudent Aug 18 '21 at 11:06
  • 1
    `whereIn` might only work for arrays with a max length of 10, as [described here](https://stackoverflow.com/a/64574629/6272061). – dcts Aug 18 '21 at 11:14
  • 1
    OP can do `x` amount of queries for as large as the list is, if the list of bus stops is larger than 10, for example 20, two queries can be done, each time for 10 according to their index. Can be solved easily with simple method to determine list.length. This is why `whereIn` was created. – Huthaifa Muayyad Aug 18 '21 at 11:20
  • I tried using `whereIn` I am able to print it out in the Log. It means that i successfully retrieve the data I want. – randomstudent Aug 18 '21 at 11:26
  • I think the error message I receive is because of `location.documents[i]` as it is a `Int` and it can not be safe as `String` I suppose. – randomstudent Aug 18 '21 at 11:30
  • 1
    Great that it works, post the error so we can work with it. – Huthaifa Muayyad Aug 18 '21 at 12:16
  • Sir I have 1 more question if my List is in a sequence and if I called that data from the Firestore can it be the same sequence? The sample of the List [Test2, Test3, Test1] but when retrieving from Firestore it became [Test1, Test2, Test3]. Any idea how to work around this sir? – randomstudent Aug 18 '21 at 14:05
  • 1
    This is because Firestore sorts them alphabetically using upper and lowercase and numbers. If you want them in the same sequence as your original list, you can build the `Listview` in reference to the original list, and when you want the bus object retrieved from firebase, you can tell your code to get the bus object from the retrived list where the object.name[from new list] == bustopName[from old list]. – Huthaifa Muayyad Aug 18 '21 at 14:14
  • But if i want to used it to store it back into the Firestore is it the same case with this? The reason i want to store it back in is that i am planning to use this to get the coordinates of the data and make a polyline so the sequence is needed for this case. – randomstudent Aug 18 '21 at 14:19
  • 1
    Store the polyline using a `Map`, with id's for the markers\LatLng. Otherwise, firebase will sort them binary wise. To validate, go to any document, and create a new field, regardless what its name is, and add a field called 'z'. Then add another field called `a`, it'll be listed on top of it. This is also the same for document names, they are sorted alpahtebtically and numerically. – Huthaifa Muayyad Aug 18 '21 at 14:24
  • `Firestore.instance.collection('routes').document(inputName).setData({ dataInt:{ "Lat" : data['location'].latitude, "Lng" : data['location'].longitude } });` If i do something like this they will only store one of the Item in the List right? How can i store all of them then in a single Document – randomstudent Aug 18 '21 at 15:00
  • 1
    Sorry sir i think i will start asking a new question this comment is getting longer and longer hahaha. Thank you so much for your help till now. Maybe you will be the one who answer my next question as well. hahahaha Thank you so much once again. – randomstudent Aug 18 '21 at 15:08
  • 1
    Anytime mate, happy coding :) – Huthaifa Muayyad Aug 18 '21 at 15:10
1

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.

dcts
  • 1,479
  • 15
  • 34
1

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

dcts
  • 1,479
  • 15
  • 34