То, о чем вы просите, это запрос Cloud Firestore, который не может быть обработан, так как мы не можем сделать это общим c способом, который масштабируется независимо от данных. Есть несколько приемов, которые вы можете использовать, чтобы уменьшить сложность запросов, что означает уменьшение количества запросов, на которые вам нужно разбить это.
preferences.lookingFor
Для условия where('preferences.lookingFor', 'array-contains-any', docDataPreferences.lookingFor)
Предполагая, что возможные различные значения ограничены, а общее число известно, вы можете создать отображение возможностей и уменьшить его до единого равенства. Например,
Давайте предположим, что 3 возможных значения A
, B
и C
, и что у вас должно быть по крайней мере 1. Это означает, что есть только 7 различных запросов вариации, которые могут быть закодированы как последовательность логических полей:
preferences.lookingForCheck = {
A: <if A>,
B: <If B>,
C: <If C>,
AB: <if A OR B>,
AC: <If A OR C>,
BC: <If B OR C>,
ABC: <if A OR B OR C>,
}
Они довольно просты для вычисления во время записи и означают, что вы можете легко вычислить, к какому полю запрашивать: where('preferences.lookingForCheck.BC', '==', true)
info.languages
Это, вероятно, расширение для того, чтобы хотеть взрываться как комбинации, поэтому давайте оставим это.
age
Я упрощу и предположим несколько простых блоков, так: 21-30
, 31-44
, 45-64
, 65+
. Вы можете сделать это явные поля, как указано выше (A, B, C, D), что будет 15 полей. Если вы можете предположить, что диапазон будет непрерывным (например, если выбрано 21-30
& '45 -64 ', тогда 31-30
должно быть выбрано), вы можете оптимизировать еще больше, указав вместо этого 2 списка значений, из которых пользователи должен выбрать один из каждого, и значение во втором должно быть равно или больше, чем второе: lower_age: [21, 31, 45, 65+] upper_age: [30, 44, 64, 65 +]
Как вам нужно только 10 комбинаций с истинным / ложным значением: 21-30, 21-44, 21-64, 21-65+, 30-44, 30-64, 30-65+, 45-65, 45-65+, 65+-65+
профессия
Это еще одна сложная задача. Поскольку мы уже зафиксировали info.languages
, мы не можем иметь это как запрос, содержащий массив. У нас есть несколько вариантов для рассмотрения.
- Выполните 1 запрос для каждого типа профессии и объедините результаты на стороне клиента. Это больше кода, но прямо вперед.
- Не запрашивайте это поле вообще, а отфильтруйте все документы, которые не соответствуют на стороне клиента. Предполагается, что количество ложных совпадений невелико, в противном случае вы будете читать много документов, которые в итоге отбрасываете.
- Гибридный подход, при котором вы объединяете профессии (например, [белый, синий, розовый] ошейник) и тот же подход обсуждался для других полей, тогда как на стороне клиента выполнялась фильтрация по специфицированной c профессии.
Окончательный запрос
Следуя вышеизложенному, вы получите что-то вроде:
preferences = `preferences.lookingForCheck.${prefCombo}`;
ageRange = `ageRange.${lowerRange}to${upperRange}`;
var usersMatchesCollection = config.db.collection("Users");
var currentUserMatchesAllData = usersMatchesCollection.where(preferences, '==', docDataPreferences.lookingForMatch)
.where('info.identifyAs', '==', docDataPreferences.prefIdentifyAs)
.where('info.languages', 'array-contains-any', docDataPreferences.prefLanguages)
.where(ageRange, '==', docDataPreferences.ageRange)
.where('profession', '==', docDataPreferences.prefProfessionCollarCheck)
.where('education', '==', docDataPreferences.prefEducation)
.where('kids', '==', docDataPreferences.prefKids)
.where('married', '==', docDataPreferences.prefMarried)
.where('drinking', '==', docDataPreferences.prefDrinking)
.where('smokingCig', '==', docDataPreferences.prefSmokingCig)
await currentUserMatchesAllData.get().then( function (matchesQuerySnapshot) {
matchesQuerySnapshot.forEach(function(doc) {
// Filter by profession here
console.log('doc data: ' + JSON.stringify(doc.data().id));
})
})