[英]How to perform compound queries with logical OR in Cloud Firestore?
从文档:
您还可以链接多个 where() 方法来创建更具体的查询(逻辑与)。
如何执行OR
查询? 例子:
status
为open
或upcoming
的文件status == open
或createdAt <= <somedatetime>
的文档 OR
不受支持,因为服务器很难对其进行扩展(需要将状态保持为重复数据删除)。 解决方法是发出 2 个查询,每个条件一个,并在客户端上进行重复数据删除。
编辑(2019 年 11 月):
Cloud Firestore 现在支持IN
查询,这是一种有限类型的OR
查询。
对于上面的示例,您可以执行以下操作:
// Get all documents in 'foo' where status is open or upcmoming
db.collection('foo').where('status','in',['open','upcoming']).get()
但是,仍然无法执行涉及多个字段的一般OR
条件。
随着最近添加的 IN 查询,Firestore 支持“同一字段上最多 10 个具有逻辑OR 的相等子句”
(1) 的可能解决方案是:
documents.where('status', 'in', ['open', 'upcoming']);
建议也为地位赋予价值。
前任。
{ name: "a", statusValue = 10, status = 'open' }
{ name: "b", statusValue = 20, status = 'upcoming'}
{ name: "c", statusValue = 30, status = 'close'}
您可以通过ref.where('statusValue', '<=', 20)
然后会找到'a'
和'b'
。
这可以节省您的查询成本和性能。
顺便说一句,它不是解决所有情况。
我不会有“状态”字段,而是与状态相关的字段,根据请求将它们更新为 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)...
希望能帮助到你。
您可以使用 rxjs 合并运算符绑定两个 Observable。 这里有一个例子。
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);
我希望这可以帮助你,来自智利的问候!!
我们刚才遇到了同样的问题,幸运的是我们的唯一可能的值是 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!
都这样做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”)
注意:如果您有几个可能的值来比较 OR,这只是一种合理的方法。
关于Array-contains 的更多信息在这里,因为它对 firebase docs 来说是新的
这并不能解决所有情况,但对于“枚举”字段,您可以通过为每个枚举值创建一个单独的布尔字段来模拟“或”查询,然后添加一个where("enum_<value>", "==", false)
对于不是您想要的“OR”子句的一部分的每个值。
例如,考虑您想要的第一个查询:
- 给我字段状态为打开或即将到来的所有文档
您可以通过将status: string
字段拆分为多个布尔字段来实现这一点,每个枚举值对应一个:
status_open: bool
status_upcoming: bool
status_suspended: bool
status_closed: bool
要执行“where status is open orcoming”查询,请执行以下操作:
where("status_suspended", "==", false).where("status_closed", "==", false)
这是如何运作的? 好吧,因为它是一个枚举,所以您知道其中一个值必须被赋值为true
。 因此,如果您可以确定所有其他值与给定条目都不匹配,那么通过推导,它必须与您最初寻找的值之一匹配。
in
/ not-in
/ array-contains-in
: https : //firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any
!=
: https://firebase.googleblog.com/2020/09/cloud-firestore-not-equal-queries.html
如果您的字段数量有限,请务必像上面的示例一样创建具有 true 和 false 的新字段。 但是,如果您在运行时之前不知道字段是什么,则必须组合查询。
这是一个标签或示例...
// the ids of students in class
const students = [studentID1, studentID2,...];
// get all docs where student.studentID1 = true
const results = this.afs.collection('classes',
ref => ref.where(`students.${students[0]}`, '==', true)
).valueChanges({ idField: 'id' }).pipe(
switchMap((r: any) => {
// get all docs where student.studentID2...studentIDX = true
const docs = students.slice(1).map(
(student: any) => this.afs.collection('classes',
ref => ref.where(`students.${student}`, '==', true)
).valueChanges({ idField: 'id' })
);
return combineLatest(docs).pipe(
// combine results by reducing array
map((a: any[]) => {
const g: [] = a.reduce(
(acc: any[], cur: any) => acc.concat(cur)
).concat(r);
// filter out duplicates by 'id' field
return g.filter(
(b: any, n: number, a: any[]) => a.findIndex(
(v: any) => v.id === b.id) === n
);
}),
);
})
);
不幸的是,没有其他方法可以组合超过 10 个项目(如果 < 10 个项目,请使用 array-contains-any)。
也没有其他方法可以避免重复读取,因为您不知道搜索将匹配的 ID 字段。 幸运的是,Firebase 有很好的缓存。
对于那些喜欢承诺的人......
const p = await results.pipe(take(1)).toPromise();
有关这方面的更多信息,请参阅我写的这篇文章。
J
或不支持
但是如果你需要,你可以在你的代码中做到
例如:如果我想查询产品 where( Size Equal Xl OR XXL : AND Gender is Male)
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);
});
对于 Flutter dart 语言,请使用:
db.collection("projects").where("status", whereIn: ["public", "unlisted", "secret"]);
实际上,我发现 @Dan McGrath 在这里工作的答案是对他的答案的重写:
private void query() {
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("STATUS")
.whereIn("status", Arrays.asList("open", "upcoming")) // you can add up to 10 different values like : Arrays.asList("open", "upcoming", "Pending", "In Progress", ...)
.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) {
for (DocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
// I assume you have a model class called MyStatus
MyStatus status= documentSnapshot.toObject(MyStatus.class);
if (status!= null) {
//do somthing...!
}
}
}
});
}
我不喜欢每个人都说这是不可能的。
如果您在模型中创建另一个“hacky”字段来构建复合...
例如,为每个包含所有逻辑或元素的文档创建一个数组
然后查询 .where("field", arrayContains: [...]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.