Flutter .where и .orderBy запросы против проблемы Firebase - PullRequest
1 голос
/ 14 июля 2020

Я пишу приложение Flutter, которое использует местоположение пользователя для определения предметов вокруг него. Поскольку в Firebase можно выполнять запросы сравнения только по одному полю, я использую геохеши в соответствии с лекцией Фрэнка ван Пуффелена по этому вопросу.

У меня начальный запрос работает нормально:

qs = await Firestore.instance
        .collection('users')
        .where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
        .where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
        .getDocuments();

возвращает всех людей в требуемой географической c области, как и ожидалось. Проблема в том, что я ожидаю, что будет много пользователей, поэтому я хочу ограничить количество загрузок для каждого запроса определенным числом - скажем, 10.

Когда я пишу этот запрос (который, как я полагал, должен сделать трюк), на самом деле кажется, что таблица упорядочена по ' geoha sh', затем она запрашивает первые 10 элементов в таблице, а затем отправляет мне записи в первых 10 элементах, которые соответствуют требованиям . где часть запроса:

qs = await Firestore.instance
          .collection('users')
          .orderBy('geohash')
          .where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
          .where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
          .startAfterDocument(dS)
          .limit(10)
          .getDocuments();

//dS = last document from previous query

, тогда как то, что я хочу, чтобы запрос выполнял всегда отправьте мне 10 результатов, все из которых выполняют часть запроса . Где .

Используя созданную мной тестовую базу данных, вызывая начальную запрос возвращает 114 результатов. Второй обнаруживает 2, что подводит меня к моему заключению о том, что происходит.

Можно ли достичь того, что я пытаюсь сделать? И если да, то какие-нибудь подсказки относительно того, что я делаю не так?

EDIT

По запросу Фрэнка dS заполняется следующим образом:

if (qs != null) {
     dS = qs.documents[qs.documents.length - 1];
}

//dS is a global variable

EDIT 2

Вот функция, которая выполняет запрос к базе данных.

Future<List<CutDownUserProfile>> getReducedUserDataBetweenGeohashes(
      String boundaryGeoHash1, String boundaryGeoHash2, DocumentSnapshot dS, int downloadLimit) async {
    List<CutDownUserProfile> retn = List<CutDownUserProfile>();

    QuerySnapshot qs;
    if (dS != null) {
      print('ds != null');
      print('dS.userNumber = ' + dS.data['userNumber'].toString());
      print('dS.userID = ' + dS.data['userID']);
      print('dS.geohash = ' + dS.data['geohash']);
      print('dS.name = ' + dS.data['name']);

      qs = await Firestore.instance
          .collection('userHeaders')
          .orderBy('geohash')
          .where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
          .where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
          .startAfterDocument(dS)
          .limit(downloadLimit)
          .getDocuments();
    } else {
      print('ds == null');
      qs = await Firestore.instance
          .collection('userHeaders')
          .orderBy('geohash')
          .where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
          .where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
          .limit(downloadLimit)
          .getDocuments();
    }
    if (qs.documents.isNotEmpty) {
      print('through this! qs len = ' + qs.documents.length.toString());
      List<DocumentSnapshot> ds = qs.documents.toList();

      print('/////DS Len = ' + ds.length.toString());
      for (int i = 0; i < ds.length; i++) {
        CutDownUserProfile cDUP = CutDownUserProfile();

        cDUP.geoHash = ds[i].data['geohash'];
        Vector2 latLon = globals.decodeGeohash(cDUP.geoHash);

        double dist = getDistanceFromLatLonInKm(globals.localUser.homeLat, globals.localUser.homeLon, latLon.x, latLon.y);

        if (dist <= globals.localUser.maxDistance && dist <= ds[i].data['maxDist']) {
            CutDownUserProfile cDUP2 = CutDownUserProfile();

            cDUP2.userNumber = ds[i].data['userNumber'];
            cDUP2.userID = ds[i].data['userID'];
            cDUP2.geoHash = ds[i].data['geohash'];

            retn.add(cDUP2);
        }
      }
      if (qs != null) {
        globals.lastProfileSeen = qs.documents[qs.documents.length - 1];
      }
    } else {
      print('no results');
    }
}

Строка print('/////DS Len = ' + ds.length.toString()); выводит длину запросы, возвращенные из поиска, и, как упоминалось ранее, возвращают 2. Без .orderBy, .startAfterDocument(dS) и .limit(downloadLimit) код возвращает 114 результатов, что я и ожидал. Для полноты, вот исходный код:

Future<List<CutDownUserProfile>> getReducedUserDataBetweenGeohashesALL(String boundaryGeoHash1, String boundaryGeoHash2) async {
    List<CutDownUserProfile> retn = List<CutDownUserProfile>();

    await Firestore.instance
        .collection('userHeaders')
        .where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
        .where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
        .getDocuments()
        .then((event) {
      if (event.documents.isNotEmpty) {
        List<DocumentSnapshot> ds = event.documents.toList(); //if it is a single document

        print('/////DS Len = ' + ds.length.toString());
        for (int i = 0; i < ds.length; i++) {
          CutDownUserProfile cDUP = CutDownUserProfile();

          cDUP.geoHash = ds[i].data['geohash'];
          Vector2 latLon = globals.decodeGeohash(cDUP.geoHash);

          double dist = getDistanceFromLatLonInKm(globals.localUser.homeLat, globals.localUser.homeLon, latLon.x, latLon.y);

          CutDownUserProfile cDUP2 = CutDownUserProfile();

          cDUP2.userNumber = ds[i].data['userNumber'];
          cDUP2.userID = ds[i].data['userID'];
          cDUP2.geoHash = ds[i].data['geohash'];

          retn.add(cDUP2);
        }
      } else {
        print('no results');
      }
    }).catchError((e) => print("error fetching data: $e"));
...