Я пишу приложение 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"));