Пределы Firebase Один «массив-содержит-любой» на запрос - что делать, если мне нужно несколько? - PullRequest
0 голосов
/ 07 февраля 2020

Подобно состояниям вопроса, Firebase допускает только один массив-любой-любой на запрос (https://firebase.google.com/docs/firestore/query-data/queries).

Что происходит, когда кому-то нужен сложный запрос? Мне нужно около 10 .where() с 4 array-contains-any предложениями на мой запрос. Есть ли обходной путь или мне нужно взять результаты из первого array-contains-any, а затем снова и снова вызывать? Кажется, облагаться налогом и не нужно.

var usersMatchesCollection = config.db.collection("Users");
var currentUserMatchesAllData = usersMatchesCollection.where('preferences.lookingFor', 'array-contains-any', docDataPreferences.lookingFor)
.where('info.identifyAs', '==', docDataPreferences.prefIdentifyAs)
.where('info.languages', 'array-contains-any', docDataPreferences.prefLanguages) 
.where('age', 'array-contains-any', docDataPreferences.ageRange) 
.where('profession', 'array-contains-any', docDataPreferences.prefProfession) 
.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) {
      console.log('doc data: ' + JSON.stringify(doc.data().id));
  })
})

1 Ответ

1 голос
/ 07 февраля 2020

То, о чем вы просите, это запрос 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. Выполните 1 запрос для каждого типа профессии и объедините результаты на стороне клиента. Это больше кода, но прямо вперед.
  2. Не запрашивайте это поле вообще, а отфильтруйте все документы, которые не соответствуют на стороне клиента. Предполагается, что количество ложных совпадений невелико, в противном случае вы будете читать много документов, которые в итоге отбрасываете.
  3. Гибридный подход, при котором вы объединяете профессии (например, [белый, синий, розовый] ошейник) и тот же подход обсуждался для других полей, тогда как на стороне клиента выполнялась фильтрация по специфицированной 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));
  })
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...