Как выполнять сложные запросы с логическим ИЛИ в 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);
});