Как выполнять сложные запросы с логическим ИЛИ в Cloud Firestore?

От документы:

Вы также можете связать несколько методов where() для создания более конкретных запросов (логическое И).

Как выполнить запрос OR? Пример:

  • Дайте мне все документы, где поле status равно open ИЛИ upcoming
  • Дайте мне все документы, где поле status == open ИЛИ createdAt <= <somedatetime>

Ответ 1

OR не поддерживается, так как это сложно для сервера, чтобы масштабировать его (требуется сохранить состояние для дедупликации). Работа вокруг состоит в том, чтобы выпустить 2 запроса, по одному для каждого условия и дедуляцию на клиенте.

Ответ 2

вы можете связать две Observables с помощью оператора слияния rxjs. Здесь у вас есть пример.

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/merge';

...

getCombinatedStatus(): Observable<any> {
   return Observable.merge(this.db.collection('foo', ref => ref.where('status','==','open')).valueChanges(),
                           this.db.collection('foo', ref => ref.where('status','==','upcoming')).valueChanges());
}

Затем вы можете подписаться на новые обновления Observable, используя описанный выше метод:

getCombinatedStatus.subscribe(results => console.log(results);

Надеюсь, это поможет вам, привет из Чили!

Ответ 3

У меня не было бы поля "status", но были бы поля, связанные со статусом, с обновлением их до true или false в зависимости от запроса, например

{ name: "a", status_open: true, status_upcoming: false, status_closed: false}

Тем не менее, проверьте Firebase Cloud Functions. Вы могли бы иметь функцию прослушивания изменений состояния, обновляя связанные с состоянием свойства, такие как

{ name: "a", status: "open", status_open: true, status_upcoming: false, status_closed: false}

один или другой, ваш запрос может быть просто

...where('status_open','==',true)...

Надеюсь, это поможет.

Ответ 4

предлагаю также дать значение для статуса.
экс.

{ name: "a", statusValue = 10, status = 'open' }

{ name: "b", statusValue = 20, status = 'upcoming'}

{ name: "c", statusValue = 30, status = 'close'}

вы можете запросить ref.where('statusValue', '<=', 20), тогда будут найдены как 'a', так и 'b'.

это может сэкономить ваши затраты и производительность.

btw, он не фиксирует все случаи.

Ответ 5

У нас сейчас такая же проблема, к счастью, единственными возможными значениями для нас являются A, B, C, D (4), поэтому мы должны запросить такие вещи, как A || B, A || C, A || B || C, D и т.д.


Как и несколько месяцев назад, Firebase поддерживает новый запрос array-contains, поэтому мы делаем массив и предварительно обрабатываем значения OR в массиве

if (a) {
array addObject:@"a"
}
if (b) {
array addObject:@"b"
}
if (a||b) {
array addObject:@"a||b"
}
etc

И мы делаем это для всех значений 4! или любого количества комбинаций.

ТОГДА мы можем просто проверить запрос [document arrayContains:@"a||c"] или любой другой тип условия, который нам нужен.

Поэтому, если что-то квалифицируется только для условного A из наших 4 условных выражений (A, B, C, D), то его массив будет содержать следующие строковые литералы: @["A", "A||B", "A||C", "A||D", "A||B||C", "A||B||D", "A||C||D", "A||B||C||D"]

Затем для любой из этих OR комбинаций мы можем просто искать array-contains на том, что мы можем захотеть (например, "A || C")


Примечание. Это разумный подход, если у вас есть несколько возможных значений для сравнения ИЛИ.

Больше информации о Array - содержит здесь, так как он новичок в документах Firebase

Ответ 6

ИЛИ не поддерживается

Но если вам это нужно, вы можете сделать это в своем коде

Пример: если я хочу запрашивать продукты, где (размер равен Xl или XXL: и пол - мужской)

productsCollectionRef
                //1* first get query where can firestore handle it
                .whereEqualTo("gender", "Male")
                .addSnapshotListener((queryDocumentSnapshots, e) -> {

                    if (queryDocumentSnapshots == null)
                        return;

                    List<Product> productList = new ArrayList<>();
                    for (DocumentSnapshot snapshot : queryDocumentSnapshots.getDocuments()) {
                        Product product = snapshot.toObject(Product.class);

                        //2* then check your query OR Condition because firestore just support AND Condition
                            if (product.getSize().equals("XL") || product.getSize().equals("XXL"))
                                productList.add(product);
                    }

                    liveData.setValue(productList);

                });